Browse Source

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb

* git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (509 commits)
  V4L/DVB (7078): radio: fix sf16fmi section mismatch
  V4L/DVB (7077): bt878: remove handcrafted PCI subsystem ID check
  V4L/DVB (7075): Make a local function static
  V4L/DVB (7074): DiB7000P: correct tuning problem for 7MHz channel
  V4L/DVB (7073): DiB7070: Reception quality improved
  V4L/DVB (7072): sets the MT2060 IF1 frequency according to EEPROM
  V4L/DVB (7071): DiB0700: Start streaming the right way
  V4L/DVB (7070): Fix some tuning problems
  V4L/DVB (7069):  Support for myTV.t
  V4L/DVB (7068): Add support for WinTV Nova-T-CE driver
  V4L/DVB (7067): fix autoserach in the Hauppauge NOVA-T 500
  V4L/DVB (7066):  ASUS My Cinema U3000 Mini DVBT Tuner
  V4L/DVB (7065): Artec T14BR patches
  V4L/DVB (7063): xc5000: Fix OOPS caused by missing firmware
  V4L/DVB (7062): radio-si570x: Some fixes and new USB ID addition
  V4L/DVB (7061): radio-si470x: Some cleanups
  V4L/DVB (7060): em28xx: remove has_tuner
  V4L/DVB (7059): cx88: Ensure the tuner is reset correctly
  V4L/DVB (7058): IR corrections for the Pinnacle 800i
  V4L/DVB (7056): tuner: suppress obsolete tuner i2c address warning for XC5000 tuners
  ...
Linus Torvalds 17 years ago
parent
commit
b31fde6db2
100 changed files with 9792 additions and 1504 deletions
  1. 0 9
      Documentation/DocBook/videobook.tmpl
  2. 12 0
      Documentation/dvb/bt8xx.txt
  3. 3 1
      Documentation/video4linux/CARDLIST.cx23885
  4. 1 0
      Documentation/video4linux/CARDLIST.cx88
  5. 10 7
      Documentation/video4linux/CARDLIST.em28xx
  6. 6 0
      Documentation/video4linux/CARDLIST.ivtv
  7. 15 2
      Documentation/video4linux/CARDLIST.saa7134
  8. 3 2
      Documentation/video4linux/CARDLIST.tuner
  9. 1 0
      Documentation/video4linux/CARDLIST.usbvision
  10. 926 0
      Documentation/video4linux/extract_xc3028.pl
  11. 1 0
      Documentation/video4linux/sn9c102.txt
  12. 9 0
      MAINTAINERS
  13. 21 1
      drivers/media/Kconfig
  14. 1 1
      drivers/media/common/Kconfig
  15. 1 2
      drivers/media/common/ir-functions.c
  16. 145 1
      drivers/media/common/ir-keymaps.c
  17. 5 4
      drivers/media/common/saa7146_fops.c
  18. 5 5
      drivers/media/common/saa7146_vbi.c
  19. 4 4
      drivers/media/common/saa7146_video.c
  20. 0 1
      drivers/media/dvb/b2c2/flexcop.c
  21. 33 43
      drivers/media/dvb/bt8xx/bt878.c
  22. 0 6
      drivers/media/dvb/bt8xx/bt878.h
  23. 8 11
      drivers/media/dvb/bt8xx/dst.c
  24. 0 5
      drivers/media/dvb/bt8xx/dst_common.h
  25. 6 0
      drivers/media/dvb/dvb-core/dvb_frontend.c
  26. 35 8
      drivers/media/dvb/dvb-core/dvb_frontend.h
  27. 0 5
      drivers/media/dvb/dvb-core/dvb_ringbuffer.c
  28. 6 1
      drivers/media/dvb/dvb-usb/af9005.c
  29. 3 3
      drivers/media/dvb/dvb-usb/au6610.c
  30. 412 24
      drivers/media/dvb/dvb-usb/cxusb.c
  31. 2 5
      drivers/media/dvb/dvb-usb/cxusb.h
  32. 1 4
      drivers/media/dvb/dvb-usb/dib0700_core.c
  33. 139 10
      drivers/media/dvb/dvb-usb/dib0700_devices.c
  34. 2 1
      drivers/media/dvb/dvb-usb/digitv.c
  35. 0 3
      drivers/media/dvb/dvb-usb/digitv.h
  36. 17 1
      drivers/media/dvb/dvb-usb/dvb-usb-ids.h
  37. 3 3
      drivers/media/dvb/dvb-usb/gl861.c
  38. 0 16
      drivers/media/dvb/dvb-usb/gp8psk.c
  39. 0 1
      drivers/media/dvb/dvb-usb/gp8psk.h
  40. 4 2
      drivers/media/dvb/dvb-usb/opera1.c
  41. 0 9
      drivers/media/dvb/dvb-usb/opera1.h
  42. 1 14
      drivers/media/dvb/dvb-usb/vp702x.c
  43. 0 2
      drivers/media/dvb/dvb-usb/vp702x.h
  44. 4 1
      drivers/media/dvb/dvb-usb/vp7045.c
  45. 0 5
      drivers/media/dvb/dvb-usb/vp7045.h
  46. 16 0
      drivers/media/dvb/frontends/Kconfig
  47. 5 0
      drivers/media/dvb/frontends/Makefile
  48. 11 2
      drivers/media/dvb/frontends/dib0070.c
  49. 7 3
      drivers/media/dvb/frontends/dib3000mc.c
  50. 6 3
      drivers/media/dvb/frontends/dib7000m.c
  51. 9 9
      drivers/media/dvb/frontends/dib7000p.c
  52. 5 0
      drivers/media/dvb/frontends/dibx000_common.h
  53. 134 70
      drivers/media/dvb/frontends/mt2266.c
  54. 152 105
      drivers/media/dvb/frontends/mt312.c
  55. 7 8
      drivers/media/dvb/frontends/mt312.h
  56. 7 1
      drivers/media/dvb/frontends/mt352.c
  57. 1 5
      drivers/media/dvb/frontends/or51132.c
  58. 1 5
      drivers/media/dvb/frontends/or51211.c
  59. 76 21
      drivers/media/dvb/frontends/s5h1409.c
  60. 9 2
      drivers/media/dvb/frontends/s5h1409.h
  61. 653 0
      drivers/media/dvb/frontends/tda18271-common.c
  62. 1225 0
      drivers/media/dvb/frontends/tda18271-fe.c
  63. 212 0
      drivers/media/dvb/frontends/tda18271-priv.h
  64. 1285 0
      drivers/media/dvb/frontends/tda18271-tables.c
  65. 78 0
      drivers/media/dvb/frontends/tda18271.h
  66. 352 15
      drivers/media/dvb/frontends/tda827x.c
  67. 7 0
      drivers/media/dvb/frontends/tda827x.h
  68. 2 2
      drivers/media/dvb/frontends/ves1820.c
  69. 964 0
      drivers/media/dvb/frontends/xc5000.c
  70. 62 0
      drivers/media/dvb/frontends/xc5000.h
  71. 36 0
      drivers/media/dvb/frontends/xc5000_priv.h
  72. 288 39
      drivers/media/dvb/frontends/zl10353.c
  73. 5 4
      drivers/media/dvb/frontends/zl10353.h
  74. 21 2
      drivers/media/dvb/frontends/zl10353_priv.h
  75. 26 11
      drivers/media/dvb/ttpci/Kconfig
  76. 7 5
      drivers/media/dvb/ttpci/Makefile
  77. 2 1
      drivers/media/dvb/ttpci/av7110.c
  78. 6 1
      drivers/media/dvb/ttpci/av7110.h
  79. 10 6
      drivers/media/dvb/ttpci/av7110_av.c
  80. 2 1
      drivers/media/dvb/ttpci/av7110_av.h
  81. 2 2
      drivers/media/dvb/ttpci/av7110_v4l.c
  82. 10 0
      drivers/media/radio/Kconfig
  83. 1 0
      drivers/media/radio/Makefile
  84. 13 5
      drivers/media/radio/dsbr100.c
  85. 3 3
      drivers/media/radio/radio-gemtek.c
  86. 1 1
      drivers/media/radio/radio-maestro.c
  87. 1 1
      drivers/media/radio/radio-sf16fmi.c
  88. 1 2
      drivers/media/radio/radio-sf16fmr2.c
  89. 1432 0
      drivers/media/radio/radio-si470x.c
  90. 42 10
      drivers/media/video/Kconfig
  91. 9 1
      drivers/media/video/Makefile
  92. 1 1
      drivers/media/video/bt8xx/Kconfig
  93. 1 1
      drivers/media/video/bt8xx/Makefile
  94. 382 0
      drivers/media/video/bt8xx/bttv-audio-hook.c
  95. 23 0
      drivers/media/video/bt8xx/bttv-audio-hook.h
  96. 28 416
      drivers/media/video/bt8xx/bttv-cards.c
  97. 268 480
      drivers/media/video/bt8xx/bttv-driver.c
  98. 5 0
      drivers/media/video/bt8xx/bttv-input.c
  99. 7 7
      drivers/media/video/bt8xx/bttv-risc.c
  100. 28 30
      drivers/media/video/bt8xx/bttv-vbi.c

+ 0 - 9
Documentation/DocBook/videobook.tmpl

@@ -96,7 +96,6 @@ static struct video_device my_radio
 {
         "My radio",
         VID_TYPE_TUNER,
-        VID_HARDWARE_MYRADIO,
         radio_open.
         radio_close,
         NULL,                /* no read */
@@ -118,13 +117,6 @@ static struct video_device my_radio
         indicates that the device can be tuned. Clearly our radio is going to have some
         way to change channel so it is tuneable.
   </para>
-  <para>
-        The VID_HARDWARE_ types are unique to each device. Numbers are assigned by
-        <email>alan@redhat.com</email> when device drivers are going to be released. Until then you
-        can pull a suitably large number out of your hat and use it. 10000 should be
-        safe for a very long time even allowing for the huge number of vendors
-        making new and different radio cards at the moment.
-  </para>
   <para>
         We declare an open and close routine, but we do not need read or write,
         which are used to read and write video data to or from the card itself. As
@@ -844,7 +836,6 @@ static struct video_device my_camera
         "My Camera",
         VID_TYPE_OVERLAY|VID_TYPE_SCALES|\
         VID_TYPE_CAPTURE|VID_TYPE_CHROMAKEY,
-        VID_HARDWARE_MYCAMERA,
         camera_open.
         camera_close,
         camera_read,      /* no read */

+ 12 - 0
Documentation/dvb/bt8xx.txt

@@ -78,6 +78,18 @@ Example:
 For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv.
 In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org.
 
+2c) Probing the cards with broken PCI subsystem ID
+--------------------------------------------------
+There are some TwinHan cards that the EEPROM has become corrupted for some
+reason. The cards do not have correct PCI subsystem ID. But we can force
+probing the cards with broken PCI subsystem ID
+
+	$ echo 109e 0878 $subvendor $subdevice > \
+		/sys/bus/pci/drivers/bt878/new_id
+
+109e: PCI_VENDOR_ID_BROOKTREE
+0878: PCI_DEVICE_ID_BROOKTREE_878
+
 Authors: Richard Walker,
 	 Jamie Honan,
 	 Michael Hunold,

+ 3 - 1
Documentation/video4linux/CARDLIST.cx23885

@@ -1,5 +1,7 @@
   0 -> UNKNOWN/GENERIC                                     [0070:3400]
   1 -> Hauppauge WinTV-HVR1800lp                           [0070:7600]
-  2 -> Hauppauge WinTV-HVR1800                             [0070:7800,0070:7801]
+  2 -> Hauppauge WinTV-HVR1800                             [0070:7800,0070:7801,0070:7809]
   3 -> Hauppauge WinTV-HVR1250                             [0070:7911]
   4 -> DViCO FusionHDTV5 Express                           [18ac:d500]
+  5 -> Hauppauge WinTV-HVR1500Q                            [0070:7790,0070:7797]
+  6 -> Hauppauge WinTV-HVR1500                             [0070:7710,0070:7717]

+ 1 - 0
Documentation/video4linux/CARDLIST.cx88

@@ -56,3 +56,4 @@
  55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM  [c180:c980]
  56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder   [0070:9600,0070:9601,0070:9602]
  57 -> ADS Tech Instant Video PCI                          [1421:0390]
+ 58 -> Pinnacle PCTV HD 800i                               [11bd:0051]

+ 10 - 7
Documentation/video4linux/CARDLIST.em28xx

@@ -1,14 +1,17 @@
   0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
-  1 -> Unknown EM2820/2840 video grabber        (em2820/em2840)
+  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2750,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
   2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
   3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
-  4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200]
-  5 -> MSI VOX USB 2.0                          (em2820/em2840) [eb1a:2820]
+  4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200,2040:4201]
+  5 -> MSI VOX USB 2.0                          (em2820/em2840)
   6 -> Terratec Cinergy 200 USB                 (em2800)
   7 -> Leadtek Winfast USB II                   (em2800)
   8 -> Kworld USB2800                           (em2800)
-  9 -> Pinnacle Dazzle DVC 90                   (em2820/em2840) [2304:0207]
- 10 -> Hauppauge WinTV HVR 900                  (em2880)
- 11 -> Terratec Hybrid XS                       (em2880)
+  9 -> Pinnacle Dazzle DVC 90/DVC 100           (em2820/em2840) [2304:0207,2304:021a]
+ 10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500]
+ 11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
- 13 -> Terratec Prodigy XS                      (em2880)
+ 13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
+ 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
+ 15 -> V-Gear PocketTV                          (em2800)
+ 16 -> Hauppauge WinTV HVR 950                  (em2880)        [2040:6513]

+ 6 - 0
Documentation/video4linux/CARDLIST.ivtv

@@ -16,3 +16,9 @@
 16 -> GOTVIEW PCI DVD2 Deluxe 			[ffac:0600]
 17 -> Yuan MPC622 				[ff01:d998]
 18 -> Digital Cowboy DCT-MTVP1 			[1461:bfff]
+19 -> Yuan PG600V2/GotView PCI DVD Lite 	[ffab:0600,ffad:0600]
+20 -> Club3D ZAP-TV1x01				[ffab:0600]
+21 -> AverTV MCE 116 Plus			[1461:c439]
+22 -> ASUS Falcon2				[1043:4b66,1043:462e,1043:4b2e]
+23 -> AverMedia PVR-150 Plus			[1461:c035]
+24 -> AverMedia EZMaker PCI Deluxe		[1461:c03f]

+ 15 - 2
Documentation/video4linux/CARDLIST.saa7134

@@ -80,7 +80,7 @@
  79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
- 82 -> MSI TV@Anywhere plus                     [1462:6231]
+ 82 -> MSI TV@Anywhere plus                     [1462:6231,1462:8624]
  83 -> Terratec Cinergy 250 PCI TV              [153b:1160]
  84 -> LifeView FlyDVB Trio                     [5168:0319]
  85 -> AverTV DVB-T 777                         [1461:2c05,1461:2c05]
@@ -102,7 +102,7 @@
 101 -> Pinnacle PCTV 310i                       [11bd:002f]
 102 -> Avermedia AVerTV Studio 507              [1461:9715]
 103 -> Compro Videomate DVB-T200A
-104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid     [0070:6701]
+104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid     [0070:6700,0070:6701,0070:6702,0070:6703,0070:6704,0070:6705]
 105 -> Terratec Cinergy HT PCMCIA               [153b:1172]
 106 -> Encore ENLTV                             [1131:2342,1131:2341,3016:2344]
 107 -> Encore ENLTV-FM                          [1131:230f]
@@ -116,3 +116,16 @@
 115 -> Sabrent PCMCIA TV-PCB05                  [0919:2003]
 116 -> 10MOONS TM300 TV Card                    [1131:2304]
 117 -> Avermedia Super 007                      [1461:f01d]
+118 -> Beholder BeholdTV 401                    [0000:4016]
+119 -> Beholder BeholdTV 403                    [0000:4036]
+120 -> Beholder BeholdTV 403 FM                 [0000:4037]
+121 -> Beholder BeholdTV 405                    [0000:4050]
+122 -> Beholder BeholdTV 405 FM                 [0000:4051]
+123 -> Beholder BeholdTV 407                    [0000:4070]
+124 -> Beholder BeholdTV 407 FM                 [0000:4071]
+125 -> Beholder BeholdTV 409                    [0000:4090]
+126 -> Beholder BeholdTV 505 FM/RDS             [0000:5051,0000:505B,5ace:5050]
+127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
+128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
+129 -> Beholder BeholdTV 607 / BeholdTV 609     [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
+130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193]

+ 3 - 2
Documentation/video4linux/CARDLIST.tuner

@@ -52,7 +52,7 @@ tuner=50 - TCL 2002N
 tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
 tuner=52 - Thomson DTT 7610 (ATSC/NTSC)
 tuner=53 - Philips FQ1286
-tuner=54 - tda8290+75
+tuner=54 - Philips/NXP TDA 8290/8295 + 8275/8275A/18271
 tuner=55 - TCL 2002MB
 tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
 tuner=57 - Philips FQ1236A MK4
@@ -69,7 +69,8 @@ tuner=67 - Philips TD1316 Hybrid Tuner
 tuner=68 - Philips TUV1236D ATSC/NTSC dual in
 tuner=69 - Tena TNF 5335 and similar models
 tuner=70 - Samsung TCPN 2121P30A
-tuner=71 - Xceive xc3028
+tuner=71 - Xceive xc2028/xc3028 tuner
 tuner=72 - Thomson FE6600
 tuner=73 - Samsung TCPG 6121P30A
 tuner=75 - Philips TEA5761 FM Radio
+tuner=76 - Xceive 5000 tuner

+ 1 - 0
Documentation/video4linux/CARDLIST.usbvision

@@ -62,3 +62,4 @@
  61 -> Pinnacle Studio Linx Video input cable (PAL)             [2304:0301]
  62 -> Pinnacle PCTV Bungee USB (PAL) FM                        [2304:0419]
  63 -> Hauppauge WinTv-USB                                      [2400:4200]
+ 64 -> Pinnacle Studio PCTV USB (NTSC) FM V3                    [2304:0113]

+ 926 - 0
Documentation/video4linux/extract_xc3028.pl

@@ -0,0 +1,926 @@
+#!/usr/bin/perl
+
+# Copyright (c) Mauro Carvalho Chehab <mchehab@infradead.org>
+# Released under GPLv2
+#
+# In order to use, you need to:
+#	1) Download the windows driver with something like:
+#		wget http://www.steventoth.net/linux/xc5000/HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip
+#	2) Extract the file hcw85bda.sys from the zip into the current dir:
+#		unzip -j HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip Driver85/hcw85bda.sys
+#	3) run the script:
+#		./extract_xc3028.pl
+#	4) copy the generated file:
+#		cp xc3028-v27.fw /lib/firmware
+
+#use strict;
+use IO::Handle;
+
+my $debug=0;
+
+sub verify ($$)
+{
+	my ($filename, $hash) = @_;
+	my ($testhash);
+
+	if (system("which md5sum > /dev/null 2>&1")) {
+		die "This firmware requires the md5sum command - see http://www.gnu.org/software/coreutils/\n";
+	}
+
+	open(CMD, "md5sum ".$filename."|");
+	$testhash = <CMD>;
+	$testhash =~ /([a-zA-Z0-9]*)/;
+	$testhash = $1;
+	close CMD;
+		die "Hash of extracted file does not match (found $testhash, expected $hash!\n" if ($testhash ne $hash);
+}
+
+sub get_hunk ($$)
+{
+	my ($offset, $length) = @_;
+	my ($chunklength, $buf, $rcount, $out);
+
+	sysseek(INFILE, $offset, SEEK_SET);
+	while ($length > 0) {
+	# Calc chunk size
+		$chunklength = 2048;
+		$chunklength = $length if ($chunklength > $length);
+
+		$rcount = sysread(INFILE, $buf, $chunklength);
+		die "Ran out of data\n" if ($rcount != $chunklength);
+		$out .= $buf;
+		$length -= $rcount;
+	}
+	return $out;
+}
+
+sub write_le16($)
+{
+	my $val = shift;
+	my $msb = ($val >> 8) &0xff;
+	my $lsb = $val & 0xff;
+
+	syswrite(OUTFILE, chr($lsb).chr($msb));
+}
+
+sub write_le32($)
+{
+	my $val = shift;
+	my $l3 = ($val >> 24) & 0xff;
+	my $l2 = ($val >> 16) & 0xff;
+	my $l1 = ($val >> 8)  & 0xff;
+	my $l0 = $val         & 0xff;
+
+	syswrite(OUTFILE, chr($l0).chr($l1).chr($l2).chr($l3));
+}
+
+sub write_le64($$)
+{
+	my $msb_val = shift;
+	my $lsb_val = shift;
+	my $l7 = ($msb_val >> 24) & 0xff;
+	my $l6 = ($msb_val >> 16) & 0xff;
+	my $l5 = ($msb_val >> 8)  & 0xff;
+	my $l4 = $msb_val         & 0xff;
+
+	my $l3 = ($lsb_val >> 24) & 0xff;
+	my $l2 = ($lsb_val >> 16) & 0xff;
+	my $l1 = ($lsb_val >> 8)  & 0xff;
+	my $l0 = $lsb_val         & 0xff;
+
+	syswrite(OUTFILE,
+		 chr($l0).chr($l1).chr($l2).chr($l3).
+		 chr($l4).chr($l5).chr($l6).chr($l7));
+}
+
+sub write_hunk($$)
+{
+	my ($offset, $length) = @_;
+	my $out = get_hunk($offset, $length);
+
+	printf "(len %d) ",$length if ($debug);
+
+	for (my $i=0;$i<$length;$i++) {
+		printf "%02x ",ord(substr($out,$i,1)) if ($debug);
+	}
+	printf "\n" if ($debug);
+
+	syswrite(OUTFILE, $out);
+}
+
+sub write_hunk_fix_endian($$)
+{
+	my ($offset, $length) = @_;
+	my $out = get_hunk($offset, $length);
+
+	printf "(len_fix %d) ",$length if ($debug);
+
+	for (my $i=0;$i<$length;$i++) {
+		printf "%02x ",ord(substr($out,$i,1)) if ($debug);
+	}
+	printf "\n" if ($debug);
+
+	my $i=0;
+	while ($i<$length) {
+		my $size = ord(substr($out,$i,1))*256+ord(substr($out,$i+1,1));
+		syswrite(OUTFILE, substr($out,$i+1,1));
+		syswrite(OUTFILE, substr($out,$i,1));
+		$i+=2;
+		if ($size>0 && $size <0x8000) {
+			for (my $j=0;$j<$size;$j++) {
+				syswrite(OUTFILE, substr($out,$j+$i,1));
+			}
+			$i+=$size;
+		}
+	}
+}
+
+sub main_firmware($$$$)
+{
+	my $out;
+	my $j=0;
+	my $outfile = shift;
+	my $name    = shift;
+	my $version = shift;
+	my $nr_desc = shift;
+
+	for ($j = length($name); $j <32; $j++) {
+		$name = $name.chr(0);
+}
+
+	open OUTFILE, ">$outfile";
+	syswrite(OUTFILE, $name);
+	write_le16($version);
+	write_le16($nr_desc);
+
+	#
+	# Firmware 0, type: BASE FW   F8MHZ (0x00000003), id: (0000000000000000), size: 8718
+	#
+
+	write_le32(0x00000003);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(8718);			# Size
+	write_hunk_fix_endian(813432, 8718);
+
+	#
+	# Firmware 1, type: BASE FW   F8MHZ MTS (0x00000007), id: (0000000000000000), size: 8712
+	#
+
+	write_le32(0x00000007);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(8712);			# Size
+	write_hunk_fix_endian(822152, 8712);
+
+	#
+	# Firmware 2, type: BASE FW   FM (0x00000401), id: (0000000000000000), size: 8562
+	#
+
+	write_le32(0x00000401);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(8562);			# Size
+	write_hunk_fix_endian(830872, 8562);
+
+	#
+	# Firmware 3, type: BASE FW   FM INPUT1 (0x00000c01), id: (0000000000000000), size: 8576
+	#
+
+	write_le32(0x00000c01);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(8576);			# Size
+	write_hunk_fix_endian(839440, 8576);
+
+	#
+	# Firmware 4, type: BASE FW   (0x00000001), id: (0000000000000000), size: 8706
+	#
+
+	write_le32(0x00000001);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(8706);			# Size
+	write_hunk_fix_endian(848024, 8706);
+
+	#
+	# Firmware 5, type: BASE FW   MTS (0x00000005), id: (0000000000000000), size: 8682
+	#
+
+	write_le32(0x00000005);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(8682);			# Size
+	write_hunk_fix_endian(856736, 8682);
+
+	#
+	# Firmware 6, type: STD FW    (0x00000000), id: PAL/BG A2/A (0000000100000007), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000001, 0x00000007);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(865424, 161);
+
+	#
+	# Firmware 7, type: STD FW    MTS (0x00000004), id: PAL/BG A2/A (0000000100000007), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000001, 0x00000007);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(865592, 169);
+
+	#
+	# Firmware 8, type: STD FW    (0x00000000), id: PAL/BG A2/B (0000000200000007), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000002, 0x00000007);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(865424, 161);
+
+	#
+	# Firmware 9, type: STD FW    MTS (0x00000004), id: PAL/BG A2/B (0000000200000007), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000002, 0x00000007);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(865592, 169);
+
+	#
+	# Firmware 10, type: STD FW    (0x00000000), id: PAL/BG NICAM/A (0000000400000007), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000004, 0x00000007);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(866112, 161);
+
+	#
+	# Firmware 11, type: STD FW    MTS (0x00000004), id: PAL/BG NICAM/A (0000000400000007), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000004, 0x00000007);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(866280, 169);
+
+	#
+	# Firmware 12, type: STD FW    (0x00000000), id: PAL/BG NICAM/B (0000000800000007), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000008, 0x00000007);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(866112, 161);
+
+	#
+	# Firmware 13, type: STD FW    MTS (0x00000004), id: PAL/BG NICAM/B (0000000800000007), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000008, 0x00000007);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(866280, 169);
+
+	#
+	# Firmware 14, type: STD FW    (0x00000000), id: PAL/DK A2 (00000003000000e0), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000003, 0x000000e0);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(866800, 161);
+
+	#
+	# Firmware 15, type: STD FW    MTS (0x00000004), id: PAL/DK A2 (00000003000000e0), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000003, 0x000000e0);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(866968, 169);
+
+	#
+	# Firmware 16, type: STD FW    (0x00000000), id: PAL/DK NICAM (0000000c000000e0), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x0000000c, 0x000000e0);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(867144, 161);
+
+	#
+	# Firmware 17, type: STD FW    MTS (0x00000004), id: PAL/DK NICAM (0000000c000000e0), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x0000000c, 0x000000e0);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(867312, 169);
+
+	#
+	# Firmware 18, type: STD FW    (0x00000000), id: SECAM/K1 (0000000000200000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00200000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(867488, 161);
+
+	#
+	# Firmware 19, type: STD FW    MTS (0x00000004), id: SECAM/K1 (0000000000200000), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x00200000);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(867656, 169);
+
+	#
+	# Firmware 20, type: STD FW    (0x00000000), id: SECAM/K3 (0000000004000000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x04000000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(867832, 161);
+
+	#
+	# Firmware 21, type: STD FW    MTS (0x00000004), id: SECAM/K3 (0000000004000000), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x04000000);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(868000, 169);
+
+	#
+	# Firmware 22, type: STD FW    D2633 DTV6 ATSC (0x00010030), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00010030);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(868176, 149);
+
+	#
+	# Firmware 23, type: STD FW    D2620 DTV6 QAM (0x00000068), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000068);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(868336, 149);
+
+	#
+	# Firmware 24, type: STD FW    D2633 DTV6 QAM (0x00000070), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000070);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(868488, 149);
+
+	#
+	# Firmware 25, type: STD FW    D2620 DTV7 (0x00000088), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000088);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(868648, 149);
+
+	#
+	# Firmware 26, type: STD FW    D2633 DTV7 (0x00000090), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000090);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(868800, 149);
+
+	#
+	# Firmware 27, type: STD FW    D2620 DTV78 (0x00000108), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000108);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(868960, 149);
+
+	#
+	# Firmware 28, type: STD FW    D2633 DTV78 (0x00000110), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000110);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(869112, 149);
+
+	#
+	# Firmware 29, type: STD FW    D2620 DTV8 (0x00000208), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000208);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(868648, 149);
+
+	#
+	# Firmware 30, type: STD FW    D2633 DTV8 (0x00000210), id: (0000000000000000), size: 149
+	#
+
+	write_le32(0x00000210);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(149);			# Size
+	write_hunk_fix_endian(868800, 149);
+
+	#
+	# Firmware 31, type: STD FW    FM (0x00000400), id: (0000000000000000), size: 135
+	#
+
+	write_le32(0x00000400);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le32(135);			# Size
+	write_hunk_fix_endian(869584, 135);
+
+	#
+	# Firmware 32, type: STD FW    (0x00000000), id: PAL/I (0000000000000010), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00000010);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(869728, 161);
+
+	#
+	# Firmware 33, type: STD FW    MTS (0x00000004), id: PAL/I (0000000000000010), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x00000010);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(869896, 169);
+
+	#
+	# Firmware 34, type: STD FW    (0x00000000), id: SECAM/L AM (0000001000400000), size: 169
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000010, 0x00400000);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(870072, 169);
+
+	#
+	# Firmware 35, type: STD FW    (0x00000000), id: SECAM/L NICAM (0000000c00400000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x0000000c, 0x00400000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(870248, 161);
+
+	#
+	# Firmware 36, type: STD FW    (0x00000000), id: SECAM/Lc (0000000000800000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00800000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(870416, 161);
+
+	#
+	# Firmware 37, type: STD FW    (0x00000000), id: NTSC/M Kr (0000000000008000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(870584, 161);
+
+	#
+	# Firmware 38, type: STD FW    LCD (0x00001000), id: NTSC/M Kr (0000000000008000), size: 161
+	#
+
+	write_le32(0x00001000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(870752, 161);
+
+	#
+	# Firmware 39, type: STD FW    LCD NOGD (0x00003000), id: NTSC/M Kr (0000000000008000), size: 161
+	#
+
+	write_le32(0x00003000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(870920, 161);
+
+	#
+	# Firmware 40, type: STD FW    MTS (0x00000004), id: NTSC/M Kr (0000000000008000), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(871088, 169);
+
+	#
+	# Firmware 41, type: STD FW    (0x00000000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(871264, 161);
+
+	#
+	# Firmware 42, type: STD FW    LCD (0x00001000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+	#
+
+	write_le32(0x00001000);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(871432, 161);
+
+	#
+	# Firmware 43, type: STD FW    LCD NOGD (0x00003000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161
+	#
+
+	write_le32(0x00003000);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(871600, 161);
+
+	#
+	# Firmware 44, type: STD FW    (0x00000000), id: NTSC/M Jp (0000000000002000), size: 161
+	#
+
+	write_le32(0x00000000);			# Type
+	write_le64(0x00000000, 0x00002000);	# ID
+	write_le32(161);			# Size
+	write_hunk_fix_endian(871264, 161);
+
+	#
+	# Firmware 45, type: STD FW    MTS (0x00000004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+	#
+
+	write_le32(0x00000004);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(871936, 169);
+
+	#
+	# Firmware 46, type: STD FW    MTS LCD (0x00001004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+	#
+
+	write_le32(0x00001004);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(872112, 169);
+
+	#
+	# Firmware 47, type: STD FW    MTS LCD NOGD (0x00003004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169
+	#
+
+	write_le32(0x00003004);			# Type
+	write_le64(0x00000000, 0x0000b700);	# ID
+	write_le32(169);			# Size
+	write_hunk_fix_endian(872288, 169);
+
+	#
+	# Firmware 48, type: SCODE FW  HAS IF (0x60000000), IF = 3.28 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(3280);			# IF
+	write_le32(192);			# Size
+	write_hunk(811896, 192);
+
+	#
+	# Firmware 49, type: SCODE FW  HAS IF (0x60000000), IF = 3.30 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(3300);			# IF
+	write_le32(192);			# Size
+	write_hunk(813048, 192);
+
+	#
+	# Firmware 50, type: SCODE FW  HAS IF (0x60000000), IF = 3.44 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(3440);			# IF
+	write_le32(192);			# Size
+	write_hunk(812280, 192);
+
+	#
+	# Firmware 51, type: SCODE FW  HAS IF (0x60000000), IF = 3.46 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(3460);			# IF
+	write_le32(192);			# Size
+	write_hunk(812472, 192);
+
+	#
+	# Firmware 52, type: SCODE FW  DTV6 ATSC OREN36 HAS IF (0x60210020), IF = 3.80 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60210020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(3800);			# IF
+	write_le32(192);			# Size
+	write_hunk(809784, 192);
+
+	#
+	# Firmware 53, type: SCODE FW  HAS IF (0x60000000), IF = 4.00 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4000);			# IF
+	write_le32(192);			# Size
+	write_hunk(812088, 192);
+
+	#
+	# Firmware 54, type: SCODE FW  DTV6 ATSC TOYOTA388 HAS IF (0x60410020), IF = 4.08 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60410020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4080);			# IF
+	write_le32(192);			# Size
+	write_hunk(809976, 192);
+
+	#
+	# Firmware 55, type: SCODE FW  HAS IF (0x60000000), IF = 4.20 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4200);			# IF
+	write_le32(192);			# Size
+	write_hunk(811704, 192);
+
+	#
+	# Firmware 56, type: SCODE FW  MONO HAS IF (0x60008000), IF = 4.32 MHz id: NTSC/M Kr (0000000000008000), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le16(4320);			# IF
+	write_le32(192);			# Size
+	write_hunk(808056, 192);
+
+	#
+	# Firmware 57, type: SCODE FW  HAS IF (0x60000000), IF = 4.45 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4450);			# IF
+	write_le32(192);			# Size
+	write_hunk(812664, 192);
+
+	#
+	# Firmware 58, type: SCODE FW  HAS IF (0x60000000), IF = 4.50 MHz id: NTSC/M Jp (0000000000002000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00002000);	# ID
+	write_le16(4500);			# IF
+	write_le32(192);			# Size
+	write_hunk(807672, 192);
+
+	#
+	# Firmware 59, type: SCODE FW  LCD NOGD IF HAS IF (0x60023000), IF = 4.60 MHz id: NTSC/M Kr (0000000000008000), size: 192
+	#
+
+	write_le32(0x60023000);			# Type
+	write_le64(0x00000000, 0x00008000);	# ID
+	write_le16(4600);			# IF
+	write_le32(192);			# Size
+	write_hunk(807864, 192);
+
+	#
+	# Firmware 60, type: SCODE FW  DTV78 ZARLINK456 HAS IF (0x62000100), IF = 4.76 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x62000100);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4760);			# IF
+	write_le32(192);			# Size
+	write_hunk(807288, 192);
+
+	#
+	# Firmware 61, type: SCODE FW  HAS IF (0x60000000), IF = 4.94 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(4940);			# IF
+	write_le32(192);			# Size
+	write_hunk(811512, 192);
+
+	#
+	# Firmware 62, type: SCODE FW  DTV7 ZARLINK456 HAS IF (0x62000080), IF = 5.26 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x62000080);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(5260);			# IF
+	write_le32(192);			# Size
+	write_hunk(810552, 192);
+
+	#
+	# Firmware 63, type: SCODE FW  MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x00000008, 0x00000007);	# ID
+	write_le16(5320);			# IF
+	write_le32(192);			# Size
+	write_hunk(810744, 192);
+
+	#
+	# Firmware 64, type: SCODE FW  DTV8 CHINA HAS IF (0x64000200), IF = 5.40 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x64000200);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(5400);			# IF
+	write_le32(192);			# Size
+	write_hunk(807096, 192);
+
+	#
+	# Firmware 65, type: SCODE FW  DTV6 ATSC OREN538 HAS IF (0x60110020), IF = 5.58 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60110020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(5580);			# IF
+	write_le32(192);			# Size
+	write_hunk(809592, 192);
+
+	#
+	# Firmware 66, type: SCODE FW  HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2/B (0000000200000007), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000002, 0x00000007);	# ID
+	write_le16(5640);			# IF
+	write_le32(192);			# Size
+	write_hunk(808440, 192);
+
+	#
+	# Firmware 67, type: SCODE FW  HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000008, 0x00000007);	# ID
+	write_le16(5740);			# IF
+	write_le32(192);			# Size
+	write_hunk(808632, 192);
+
+	#
+	# Firmware 68, type: SCODE FW  DTV7 DIBCOM52 HAS IF (0x61000080), IF = 5.90 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x61000080);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(5900);			# IF
+	write_le32(192);			# Size
+	write_hunk(810360, 192);
+
+	#
+	# Firmware 69, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/I (0000000000000010), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x00000000, 0x00000010);	# ID
+	write_le16(6000);			# IF
+	write_le32(192);			# Size
+	write_hunk(808824, 192);
+
+	#
+	# Firmware 70, type: SCODE FW  DTV6 QAM F6MHZ HAS IF (0x68000060), IF = 6.20 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x68000060);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(6200);			# IF
+	write_le32(192);			# Size
+	write_hunk(809400, 192);
+
+	#
+	# Firmware 71, type: SCODE FW  HAS IF (0x60000000), IF = 6.24 MHz id: PAL/I (0000000000000010), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000010);	# ID
+	write_le16(6240);			# IF
+	write_le32(192);			# Size
+	write_hunk(808248, 192);
+
+	#
+	# Firmware 72, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.32 MHz id: SECAM/K1 (0000000000200000), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x00000000, 0x00200000);	# ID
+	write_le16(6320);			# IF
+	write_le32(192);			# Size
+	write_hunk(811320, 192);
+
+	#
+	# Firmware 73, type: SCODE FW  HAS IF (0x60000000), IF = 6.34 MHz id: SECAM/K1 (0000000000200000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00200000);	# ID
+	write_le16(6340);			# IF
+	write_le32(192);			# Size
+	write_hunk(809208, 192);
+
+	#
+	# Firmware 74, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.50 MHz id: SECAM/K3 (0000000004000000), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x00000000, 0x04000000);	# ID
+	write_le16(6500);			# IF
+	write_le32(192);			# Size
+	write_hunk(811128, 192);
+
+	#
+	# Firmware 75, type: SCODE FW  DTV6 ATSC ATI638 HAS IF (0x60090020), IF = 6.58 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60090020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(6580);			# IF
+	write_le32(192);			# Size
+	write_hunk(807480, 192);
+
+	#
+	# Firmware 76, type: SCODE FW  HAS IF (0x60000000), IF = 6.60 MHz id: PAL/DK A2 (00000003000000e0), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000003, 0x000000e0);	# ID
+	write_le16(6600);			# IF
+	write_le32(192);			# Size
+	write_hunk(809016, 192);
+
+	#
+	# Firmware 77, type: SCODE FW  MONO HAS IF (0x60008000), IF = 6.68 MHz id: PAL/DK A2 (00000003000000e0), size: 192
+	#
+
+	write_le32(0x60008000);			# Type
+	write_le64(0x00000003, 0x000000e0);	# ID
+	write_le16(6680);			# IF
+	write_le32(192);			# Size
+	write_hunk(810936, 192);
+
+	#
+	# Firmware 78, type: SCODE FW  DTV6 ATSC TOYOTA794 HAS IF (0x60810020), IF = 8.14 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60810020);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(8140);			# IF
+	write_le32(192);			# Size
+	write_hunk(810168, 192);
+
+	#
+	# Firmware 79, type: SCODE FW  HAS IF (0x60000000), IF = 8.20 MHz id: (0000000000000000), size: 192
+	#
+
+	write_le32(0x60000000);			# Type
+	write_le64(0x00000000, 0x00000000);	# ID
+	write_le16(8200);			# IF
+	write_le32(192);			# Size
+	write_hunk(812856, 192);
+}
+
+sub extract_firmware {
+	my $sourcefile = "hcw85bda.sys";
+	my $hash = "0e44dbf63bb0169d57446aec21881ff2";
+	my $outfile = "xc3028-v27.fw";
+	my $name = "xc2028 firmware";
+	my $version = 519;
+	my $nr_desc = 80;
+	my $out;
+
+	verify($sourcefile, $hash);
+
+	open INFILE, "<$sourcefile";
+	main_firmware($outfile, $name, $version, $nr_desc);
+	close INFILE;
+}
+
+extract_firmware;
+printf "Firmwares generated.\n";

+ 1 - 0
Documentation/video4linux/sn9c102.txt

@@ -568,6 +568,7 @@ the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
 Many thanks to following persons for their contribute (listed in alphabetical
 order):
 
+- David Anderson for the donation of a webcam;
 - Luca Capello for the donation of a webcam;
 - Philippe Coval for having helped testing the PAS202BCA image sensor;
 - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the

+ 9 - 0
MAINTAINERS

@@ -2141,6 +2141,15 @@ L:	isdn4linux@listserv.isdn4linux.de
 W:	http://www.melware.de
 S:	Maintained
 
+IVTV VIDEO4LINUX DRIVER
+P:	Hans Verkuil
+M:	hverkuil@xs4all.nl
+L:	ivtv-devel@ivtvdriver.org
+L:	ivtv-users@ivtvdriver.org
+L:	video4linux-list@redhat.com
+W:	http://www.ivtvdriver.org
+S:	Maintained
+
 JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
 P:	David Woodhouse
 M:	dwmw2@infradead.org

+ 21 - 1
drivers/media/Kconfig

@@ -69,11 +69,13 @@ source "drivers/media/common/Kconfig"
 config VIDEO_TUNER
 	tristate
 	depends on I2C
+	select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE
+	select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE
 
 menuconfig VIDEO_TUNER_CUSTOMIZE
 	bool "Customize analog tuner modules to build"
@@ -89,6 +91,13 @@ menuconfig VIDEO_TUNER_CUSTOMIZE
 
 if VIDEO_TUNER_CUSTOMIZE
 
+config TUNER_XC2028
+	tristate "XCeive xc2028/xc3028 tuners"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for the xc2028/xc3028 tuners.
+
 config TUNER_MT20XX
 	tristate "Microtune 2032 / 2050 tuners"
 	depends on I2C
@@ -97,8 +106,10 @@ config TUNER_MT20XX
 	  Say Y here to include support for the MT2032 / MT2050 tuner.
 
 config TUNER_TDA8290
-	tristate "TDA 8290+8275(a) tuner combo"
+	tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
 	depends on I2C
+	select DVB_TDA827X
+	select DVB_TDA18271
 	default m if VIDEO_TUNER_CUSTOMIZE
 	help
 	  Say Y here to include support for Philips TDA8290+8275(a) tuner.
@@ -120,10 +131,19 @@ config TUNER_TEA5767
 config TUNER_SIMPLE
 	tristate "Simple tuner support"
 	depends on I2C
+	select TUNER_TDA9887
 	default m if VIDEO_TUNER_CUSTOMIZE
 	help
 	  Say Y here to include support for various simple tuners.
 
+config TUNER_TDA9887
+	tristate "TDA 9885/6/7 analog IF demodulator"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for Philips TDA9885/6/7
+	  analog IF demodulator.
+
 endif # VIDEO_TUNER_CUSTOMIZE
 
 config VIDEOBUF_GEN

+ 1 - 1
drivers/media/common/Kconfig

@@ -1,6 +1,6 @@
 config VIDEO_SAA7146
 	tristate
-	depends on I2C
+	depends on I2C && PCI
 
 config VIDEO_SAA7146_VV
 	tristate

+ 1 - 2
drivers/media/common/ir-functions.c

@@ -258,7 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
  * saa7134 */
 
 /* decode raw bit pattern to RC5 code */
-u32 ir_rc5_decode(unsigned int code)
+static u32 ir_rc5_decode(unsigned int code)
 {
 	unsigned int org_code = code;
 	unsigned int pair;
@@ -371,7 +371,6 @@ EXPORT_SYMBOL_GPL(ir_dump_samples);
 EXPORT_SYMBOL_GPL(ir_decode_biphase);
 EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
 
-EXPORT_SYMBOL_GPL(ir_rc5_decode);
 EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
 EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
 

+ 145 - 1
drivers/media/common/ir-keymaps.c

@@ -1331,7 +1331,12 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
 	[ 0x35 ] = KEY_FASTFORWARD,
 	[ 0x36 ] = KEY_TV,
 	[ 0x37 ] = KEY_RADIO,         /* FM */
-	[ 0x38 ] = KEY_DVD
+	[ 0x38 ] = KEY_DVD,
+
+	[ 0x3e ] = KEY_F21,           /* MCE +VOL, on Y04G0033 */
+	[ 0x3a ] = KEY_F22,           /* MCE -VOL, on Y04G0033 */
+	[ 0x3b ] = KEY_F23,           /* MCE +CH,  on Y04G0033 */
+	[ 0x3f ] = KEY_F24            /* MCE -CH,  on Y04G0033 */
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_winfast);
@@ -1843,3 +1848,142 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
+
+/* Pinnacle PCTV HD 800i mini remote */
+IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = {
+
+	[0x0f] = KEY_1,
+	[0x15] = KEY_2,
+	[0x10] = KEY_3,
+	[0x18] = KEY_4,
+	[0x1b] = KEY_5,
+	[0x1e] = KEY_6,
+	[0x11] = KEY_7,
+	[0x21] = KEY_8,
+	[0x12] = KEY_9,
+	[0x27] = KEY_0,
+
+	[0x24] = KEY_ZOOM,
+	[0x2a] = KEY_SUBTITLE,
+
+	[0x00] = KEY_MUTE,
+	[0x01] = KEY_ENTER,	/* Pinnacle Logo */
+	[0x39] = KEY_POWER,
+
+	[0x03] = KEY_VOLUMEUP,
+	[0x09] = KEY_VOLUMEDOWN,
+	[0x06] = KEY_CHANNELUP,
+	[0x0c] = KEY_CHANNELDOWN,
+
+	[0x2d] = KEY_REWIND,
+	[0x30] = KEY_PLAYPAUSE,
+	[0x33] = KEY_FASTFORWARD,
+	[0x3c] = KEY_STOP,
+	[0x36] = KEY_RECORD,
+	[0x3f] = KEY_EPG,	/* Labeled "?" */
+};
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd);
+
+/*
+ * Igor Kuznetsov <igk72@ya.ru>
+ * Andrey J. Melnikov <temnota@kmv.ru>
+ *
+ * Keytable is used by BeholdTV 60x series, M6 series at
+ * least, and probably other cards too.
+ * The "ascii-art picture" below (in comments, first row
+ * is the keycode in hex, and subsequent row(s) shows
+ * the button labels (several variants when appropriate)
+ * helps to descide which keycodes to assign to the buttons.
+ */
+IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
+
+	/*  0x1c            0x12  *
+	 *  TV/FM          POWER  *
+	 *                        */
+	[ 0x1c ] = KEY_TUNER,	/*XXX KEY_TV KEY_RADIO */
+	[ 0x12 ] = KEY_POWER,
+
+	/*  0x01    0x02    0x03  *
+	 *   1       2       3    *
+	 *                        *
+	 *  0x04    0x05    0x06  *
+	 *   4       5       6    *
+	 *                        *
+	 *  0x07    0x08    0x09  *
+	 *   7       8       9    *
+	 *                        */
+	[ 0x01 ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x03 ] = KEY_3,
+	[ 0x04 ] = KEY_4,
+	[ 0x05 ] = KEY_5,
+	[ 0x06 ] = KEY_6,
+	[ 0x07 ] = KEY_7,
+	[ 0x08 ] = KEY_8,
+	[ 0x09 ] = KEY_9,
+
+	/*  0x0a    0x00    0x17  *
+	 * RECALL    0      MODE  *
+	 *                        */
+	[ 0x0a ] = KEY_AGAIN,
+	[ 0x00 ] = KEY_0,
+	[ 0x17 ] = KEY_MODE,
+
+	/*  0x14          0x10    *
+	 * ASPECT      FULLSCREEN *
+	 *                        */
+	[ 0x14 ] = KEY_SCREEN,
+	[ 0x10 ] = KEY_ZOOM,
+
+	/*          0x0b          *
+	 *           Up           *
+	 *                        *
+	 *  0x18    0x16    0x0c  *
+	 *  Left     Ok     Right *
+	 *                        *
+	 *         0x015          *
+	 *         Down           *
+	 *                        */
+	[ 0x0b ] = KEY_CHANNELUP,	/*XXX KEY_UP */
+	[ 0x18 ] = KEY_VOLUMEDOWN,	/*XXX KEY_LEFT */
+	[ 0x16 ] = KEY_OK,		/*XXX KEY_ENTER */
+	[ 0x0c ] = KEY_VOLUMEUP,	/*XXX KEY_RIGHT */
+	[ 0x15 ] = KEY_CHANNELDOWN,	/*XXX KEY_DOWN */
+
+	/*  0x11            0x0d  *
+	 *  MUTE            INFO  *
+	 *                        */
+	[ 0x11 ] = KEY_MUTE,
+	[ 0x0d ] = KEY_INFO,
+
+	/*  0x0f    0x1b    0x1a  *
+	 * RECORD PLAY/PAUSE STOP *
+	 *                        *
+	 *  0x0e    0x1f    0x1e  *
+	 *TELETEXT  AUDIO  SOURCE *
+	 *           RED   YELLOW *
+	 *                        */
+	[ 0x0f ] = KEY_RECORD,
+	[ 0x1b ] = KEY_PLAYPAUSE,
+	[ 0x1a ] = KEY_STOP,
+	[ 0x0e ] = KEY_TEXT,
+	[ 0x1f ] = KEY_RED,	/*XXX KEY_AUDIO */
+	[ 0x1e ] = KEY_YELLOW,	/*XXX KEY_SOURCE */
+
+	/*  0x1d   0x13     0x19  *
+	 * SLEEP  PREVIEW   DVB   *
+	 *         GREEN    BLUE  *
+	 *                        */
+	[ 0x1d ] = KEY_SLEEP,
+	[ 0x13 ] = KEY_GREEN,
+	[ 0x19 ] = KEY_BLUE,	/*XXX KEY_SAT */
+
+	/*  0x58           0x5c   *
+	 * FREEZE        SNAPSHOT *
+	 *                        */
+	[ 0x58 ] = KEY_SLOW,
+	[ 0x5c ] = KEY_SAVE,
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_behold);

+ 5 - 4
drivers/media/common/saa7146_fops.c

@@ -61,7 +61,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
 	videobuf_waiton(&buf->vb,0,0);
 	videobuf_dma_unmap(q, dma);
 	videobuf_dma_free(dma);
-	buf->vb.state = STATE_NEEDS_INIT;
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 
@@ -83,7 +83,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
 		buf->activate(dev,buf,NULL);
 	} else {
 		list_add_tail(&buf->vb.queue,&q->queue);
-		buf->vb.state = STATE_QUEUED;
+		buf->vb.state = VIDEOBUF_QUEUED;
 		DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf));
 	}
 	return 0;
@@ -174,7 +174,7 @@ void saa7146_buffer_timeout(unsigned long data)
 	spin_lock_irqsave(&dev->slock,flags);
 	if (q->curr) {
 		DEB_D(("timeout on %p\n", q->curr));
-		saa7146_buffer_finish(dev,q,STATE_ERROR);
+		saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
 	}
 
 	/* we don't restart the transfer here like other drivers do. when
@@ -366,7 +366,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
 	}
 
 	poll_wait(file, &buf->done, wait);
-	if (buf->state == STATE_DONE || buf->state == STATE_ERROR) {
+	if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
 		DEB_D(("poll succeeded!\n"));
 		return POLLIN|POLLRDNORM;
 	}
@@ -538,6 +538,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 	// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
 	if (video_register_device(vfd, type, -1) < 0) {
 		ERR(("cannot register v4l2 device. skipping.\n"));
+		video_device_release(vfd);
 		return -1;
 	}
 

+ 5 - 5
drivers/media/common/saa7146_vbi.c

@@ -205,7 +205,7 @@ static int buffer_activate(struct saa7146_dev *dev,
 			   struct saa7146_buf *next)
 {
 	struct saa7146_vv *vv = dev->vv_data;
-	buf->vb.state = STATE_ACTIVE;
+	buf->vb.state = VIDEOBUF_ACTIVE;
 
 	DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next));
 	saa7146_set_vbi_capture(dev,buf,next);
@@ -238,7 +238,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
 	if (buf->vb.size != size)
 		saa7146_dma_free(dev,q,buf);
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
 		buf->vb.width  = llength;
@@ -257,7 +257,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
 		if (0 != err)
 			return err;
 	}
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->activate = buffer_activate;
 
 	return 0;
@@ -335,7 +335,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
 	saa7146_write(dev, MC1, MASK_20);
 
 	if (vv->vbi_q.curr) {
-		saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
+		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
 	}
 
 	videobuf_queue_cancel(&fh->vbi_q);
@@ -458,7 +458,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
 		/* this must be += 2, one count for each field */
 		vv->vbi_fieldcount+=2;
 		vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
-		saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
+		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
 	} else {
 		DEB_VBI(("dev:%p\n",dev));
 	}

+ 4 - 4
drivers/media/common/saa7146_video.c

@@ -1235,7 +1235,7 @@ static int buffer_activate (struct saa7146_dev *dev,
 {
 	struct saa7146_vv *vv = dev->vv_data;
 
-	buf->vb.state = STATE_ACTIVE;
+	buf->vb.state = VIDEOBUF_ACTIVE;
 	saa7146_set_capture(dev,buf,next);
 
 	mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT);
@@ -1281,7 +1281,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 		saa7146_dma_free(dev,q,buf);
 	}
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		struct saa7146_format *sfmt;
 
 		buf->vb.bytesperline  = fh->video_fmt.bytesperline;
@@ -1314,7 +1314,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 		if (err)
 			goto oops;
 	}
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->activate = buffer_activate;
 
 	return 0;
@@ -1453,7 +1453,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
 
 	/* only finish the buffer if we have one... */
 	if( NULL != q->curr ) {
-		saa7146_buffer_finish(dev,q,STATE_DONE);
+		saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
 	}
 	saa7146_buffer_next(dev,q,0);
 

+ 0 - 1
drivers/media/dvb/b2c2/flexcop.c

@@ -212,7 +212,6 @@ void flexcop_reset_block_300(struct flexcop_device *fc)
 
 	fc->write_ibi_reg(fc,ctrl_208,v208_save);
 }
-EXPORT_SYMBOL(flexcop_reset_block_300);
 
 struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
 {

+ 33 - 43
drivers/media/dvb/bt8xx/bt878.c

@@ -378,23 +378,37 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
 
 EXPORT_SYMBOL(bt878_device_control);
 
+#define BROOKTREE_878_DEVICE(vend, dev, name) \
+	{ \
+		.vendor = PCI_VENDOR_ID_BROOKTREE, \
+		.device = PCI_DEVICE_ID_BROOKTREE_878, \
+		.subvendor = (vend), .subdevice = (dev), \
+		.driver_data = (unsigned long) name \
+	}
 
-static struct cards card_list[] __devinitdata = {
-
-	{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV,			"Nebula Electronics DigiTV" },
-	{ 0x07611461, BTTV_BOARD_AVDVBT_761,			"AverMedia AverTV DVB-T 761" },
-	{ 0x001c11bd, BTTV_BOARD_PINNACLESAT,			"Pinnacle PCTV Sat" },
-	{ 0x002611bd, BTTV_BOARD_TWINHAN_DST,			"Pinnacle PCTV SAT CI" },
-	{ 0x00011822, BTTV_BOARD_TWINHAN_DST,			"Twinhan VisionPlus DVB" },
-	{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST,			"ChainTech digitop DST-1000 DVB-S" },
-	{ 0x07711461, BTTV_BOARD_AVDVBT_771,			"AVermedia AverTV DVB-T 771" },
-	{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,		"DViCO FusionHDTV DVB-T Lite" },
-	{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,		"Ultraview DVB-T Lite" },
-	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,	"DViCO FusionHDTV 5 Lite" },
-	{ 0x20007063, BTTV_BOARD_PC_HDTV,			"pcHDTV HD-2000 TV" },
-	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,			"DNTV Live! Mini" }
+static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
+	BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
+	BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
+	BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
+	BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"),
+	BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"),
+	BROOKTREE_878_DEVICE(0x270f, 0xfc00,
+				"ChainTech digitop DST-1000 DVB-S"),
+	BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"),
+	BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"),
+	BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"),
+	BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"),
+	BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"),
+	BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"),
+	{ }
 };
 
+MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
+
+static const char * __devinit card_name(const struct pci_device_id *id)
+{
+	return id->driver_data ? (const char *)id->driver_data : "Unknown";
+}
 
 /***********************/
 /* PCI device handling */
@@ -403,15 +417,13 @@ static struct cards card_list[] __devinitdata = {
 static int __devinit bt878_probe(struct pci_dev *dev,
 				 const struct pci_device_id *pci_id)
 {
-	int result = 0, has_dvb = 0, i;
+	int result = 0;
 	unsigned char lat;
 	struct bt878 *bt;
 #if defined(__powerpc__)
 	unsigned int cmd;
 #endif
 	unsigned int cardid;
-	unsigned short id;
-	struct cards *dvb_cards;
 
 	printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
 	       bt878_num);
@@ -423,25 +435,11 @@ static int __devinit bt878_probe(struct pci_dev *dev,
 	if (pci_enable_device(dev))
 		return -EIO;
 
-	pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &id);
-	cardid = id << 16;
-	pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &id);
-	cardid |= id;
-
-	for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list); i++, dvb_cards++) {
-		if (cardid == dvb_cards->pci_id) {
-			printk("%s: card id=[0x%x],[ %s ] has DVB functions.\n",
-				__func__, cardid, dvb_cards->name);
-			has_dvb = 1;
-		}
-	}
+	cardid = dev->subsystem_device << 16;
+	cardid |= dev->subsystem_vendor;
 
-	if (!has_dvb) {
-		printk("%s: card id=[0x%x], Unknown card.\nExiting..\n", __func__, cardid);
-		result = -EINVAL;
-
-		goto fail0;
-	}
+	printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n",
+				__func__, cardid, card_name(pci_id));
 
 	bt = &bt878[bt878_num];
 	bt->dev = dev;
@@ -572,14 +570,6 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev)
 	return;
 }
 
-static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
-	{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0,}
-};
-
-MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
-
 static struct pci_driver bt878_pci_driver = {
       .name	= "bt878",
       .id_table = bt878_pci_tbl,

+ 0 - 6
drivers/media/dvb/bt8xx/bt878.h

@@ -101,12 +101,6 @@
 #define BTTV_BOARD_DVICO_DVBT_LITE         0x80
 #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
 
-struct cards {
-	__u32 pci_id;
-	__u16 card_id;
-	char  *name;
-};
-
 extern int bt878_num;
 
 struct bt878 {

+ 8 - 11
drivers/media/dvb/bt8xx/dst.c

@@ -71,6 +71,7 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
 	}								\
 } while(0)
 
+static int dst_command(struct dst_state *state, u8 *data, u8 len);
 
 static void dst_packsize(struct dst_state *state, int psize)
 {
@@ -80,7 +81,8 @@ static void dst_packsize(struct dst_state *state, int psize)
 	bt878_device_control(state->bt, DST_IG_TS, &bits);
 }
 
-int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay)
+static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb,
+			 u32 outhigh, int delay)
 {
 	union dst_gpio_packet enb;
 	union dst_gpio_packet bits;
@@ -109,9 +111,8 @@ int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int
 
 	return 0;
 }
-EXPORT_SYMBOL(dst_gpio_outb);
 
-int dst_gpio_inb(struct dst_state *state, u8 *result)
+static int dst_gpio_inb(struct dst_state *state, u8 *result)
 {
 	union dst_gpio_packet rd_packet;
 	int err;
@@ -125,7 +126,6 @@ int dst_gpio_inb(struct dst_state *state, u8 *result)
 
 	return 0;
 }
-EXPORT_SYMBOL(dst_gpio_inb);
 
 int rdc_reset_state(struct dst_state *state)
 {
@@ -145,7 +145,7 @@ int rdc_reset_state(struct dst_state *state)
 }
 EXPORT_SYMBOL(rdc_reset_state);
 
-int rdc_8820_reset(struct dst_state *state)
+static int rdc_8820_reset(struct dst_state *state)
 {
 	dprintk(verbose, DST_DEBUG, 1, "Resetting DST");
 	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) {
@@ -160,9 +160,8 @@ int rdc_8820_reset(struct dst_state *state)
 
 	return 0;
 }
-EXPORT_SYMBOL(rdc_8820_reset);
 
-int dst_pio_enable(struct dst_state *state)
+static int dst_pio_enable(struct dst_state *state)
 {
 	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) {
 		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
@@ -172,7 +171,6 @@ int dst_pio_enable(struct dst_state *state)
 
 	return 0;
 }
-EXPORT_SYMBOL(dst_pio_enable);
 
 int dst_pio_disable(struct dst_state *state)
 {
@@ -611,7 +609,7 @@ static int dst_type_print(struct dst_state *state, u8 type)
 	return 0;
 }
 
-struct tuner_types tuner_list[] = {
+static struct tuner_types tuner_list[] = {
 	{
 		.tuner_type = TUNER_TYPE_L64724,
 		.tuner_name = "L 64724",
@@ -1224,7 +1222,7 @@ static int dst_probe(struct dst_state *state)
 	return 0;
 }
 
-int dst_command(struct dst_state *state, u8 *data, u8 len)
+static int dst_command(struct dst_state *state, u8 *data, u8 len)
 {
 	u8 reply;
 
@@ -1287,7 +1285,6 @@ error:
 	return -EIO;
 
 }
-EXPORT_SYMBOL(dst_command);
 
 static int dst_get_signal(struct dst_state *state)
 {

+ 0 - 5
drivers/media/dvb/bt8xx/dst_common.h

@@ -165,10 +165,8 @@ struct dst_config
 };
 
 int rdc_reset_state(struct dst_state *state);
-int rdc_8820_reset(struct dst_state *state);
 
 int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
-int dst_pio_enable(struct dst_state *state);
 int dst_pio_disable(struct dst_state *state);
 int dst_error_recovery(struct dst_state* state);
 int dst_error_bailout(struct dst_state *state);
@@ -179,9 +177,6 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len);
 u8 dst_check_sum(u8 * buf, u32 len);
 struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
 struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
-int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
-
-int dst_command(struct dst_state* state, u8 * data, u8 len);
 
 
 #endif // DST_COMMON_H

+ 6 - 0
drivers/media/dvb/dvb-core/dvb_frontend.c

@@ -1202,6 +1202,10 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
 		fe->ops.tuner_ops.release(fe);
 		symbol_put_addr(fe->ops.tuner_ops.release);
 	}
+	if (fe->ops.analog_ops.release) {
+		fe->ops.analog_ops.release(fe);
+		symbol_put_addr(fe->ops.analog_ops.release);
+	}
 	ptr = (void*)fe->ops.release;
 	if (ptr) {
 		fe->ops.release(fe);
@@ -1215,6 +1219,8 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
 		fe->ops.release_sec(fe);
 	if (fe->ops.tuner_ops.release)
 		fe->ops.tuner_ops.release(fe);
+	if (fe->ops.analog_ops.release)
+		fe->ops.analog_ops.release(fe);
 	if (fe->ops.release)
 		fe->ops.release(fe);
 }

+ 35 - 8
drivers/media/dvb/dvb-core/dvb_frontend.h

@@ -84,6 +84,9 @@ struct dvb_tuner_ops {
 	/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
 	int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
 
+	/** This is to allow setting tuner-specific configs */
+	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+
 	int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
 	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
 
@@ -98,6 +101,28 @@ struct dvb_tuner_ops {
 	int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
 };
 
+struct analog_demod_info {
+	char *name;
+};
+
+struct analog_demod_ops {
+
+	struct analog_demod_info info;
+
+	void (*set_params)(struct dvb_frontend *fe,
+			   struct analog_parameters *params);
+	int  (*has_signal)(struct dvb_frontend *fe);
+	int  (*is_stereo)(struct dvb_frontend *fe);
+	int  (*get_afc)(struct dvb_frontend *fe);
+	void (*tuner_status)(struct dvb_frontend *fe);
+	void (*standby)(struct dvb_frontend *fe);
+	void (*release)(struct dvb_frontend *fe);
+	int  (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
+
+	/** This is to allow setting tuner-specific configuration */
+	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+};
+
 struct dvb_frontend_ops {
 
 	struct dvb_frontend_info info;
@@ -143,6 +168,7 @@ struct dvb_frontend_ops {
 	int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
 
 	struct dvb_tuner_ops tuner_ops;
+	struct analog_demod_ops analog_ops;
 };
 
 #define MAX_EVENT 8
@@ -159,18 +185,19 @@ struct dvb_fe_events {
 struct dvb_frontend {
 	struct dvb_frontend_ops ops;
 	struct dvb_adapter *dvb;
-	void* demodulator_priv;
-	void* tuner_priv;
-	void* frontend_priv;
-	void* sec_priv;
+	void *demodulator_priv;
+	void *tuner_priv;
+	void *frontend_priv;
+	void *sec_priv;
+	void *analog_demod_priv;
 };
 
-extern int dvb_register_frontend(struct dvb_adapter* dvb,
-				 struct dvb_frontend* fe);
+extern int dvb_register_frontend(struct dvb_adapter *dvb,
+				 struct dvb_frontend *fe);
 
-extern int dvb_unregister_frontend(struct dvb_frontend* fe);
+extern int dvb_unregister_frontend(struct dvb_frontend *fe);
 
-extern void dvb_frontend_detach(struct dvb_frontend* fe);
+extern void dvb_frontend_detach(struct dvb_frontend *fe);
 
 extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
 

+ 0 - 5
drivers/media/dvb/dvb-core/dvb_ringbuffer.c

@@ -261,11 +261,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_init);
 EXPORT_SYMBOL(dvb_ringbuffer_empty);
 EXPORT_SYMBOL(dvb_ringbuffer_free);
 EXPORT_SYMBOL(dvb_ringbuffer_avail);
-EXPORT_SYMBOL(dvb_ringbuffer_flush);
 EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_write);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_write);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);

+ 6 - 1
drivers/media/dvb/dvb-usb/af9005.c

@@ -1026,6 +1026,7 @@ static int af9005_usb_probe(struct usb_interface *intf,
 static struct usb_device_id af9005_usb_table[] = {
 	{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
 	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+	{USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)},
 	{0},
 };
 
@@ -1075,7 +1076,7 @@ static struct dvb_usb_device_properties af9005_properties = {
 	.rc_key_map_size = 0,
 	.rc_query = af9005_rc_query,
 
-	.num_device_descs = 2,
+	.num_device_descs = 3,
 	.devices = {
 		    {.name = "Afatech DVB-T USB1.1 stick",
 		     .cold_ids = {&af9005_usb_table[0], NULL},
@@ -1085,6 +1086,10 @@ static struct dvb_usb_device_properties af9005_properties = {
 		     .cold_ids = {&af9005_usb_table[1], NULL},
 		     .warm_ids = {NULL},
 		     },
+		    {.name = "Ansonic DVB-T USB1.1 stick",
+		     .cold_ids = {&af9005_usb_table[2], NULL},
+		     .warm_ids = {NULL},
+		     },
 		    {NULL},
 		    }
 };

+ 3 - 3
drivers/media/dvb/dvb-usb/au6610.c

@@ -79,12 +79,12 @@ static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
 	if (num > 2)
 		return -EINVAL;
 
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
 	for (i = 0; i < num; i++) {
 		/* write/read request */
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {

+ 412 - 24
drivers/media/dvb/dvb-usb/cxusb.c

@@ -15,7 +15,7 @@
  *
  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
  * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
- * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
+ * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au)
  *
  *   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
@@ -30,11 +30,16 @@
 #include "mt352.h"
 #include "mt352_priv.h"
 #include "zl10353.h"
+#include "tuner-xc2028.h"
+#include "tuner-xc2028-types.h"
 
 /* debug */
-int dvb_usb_cxusb_debug;
+static int dvb_usb_cxusb_debug;
 module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
+#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
+				dprintk(dvb_usb_cxusb_debug,0x01,args)
 
 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
 			  u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
@@ -46,11 +51,9 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
 	sndbuf[0] = cmd;
 	memcpy(&sndbuf[1], wbuf, wlen);
 	if (wo)
-		dvb_usb_generic_write(d, sndbuf, 1+wlen);
+		return dvb_usb_generic_write(d, sndbuf, 1+wlen);
 	else
-		dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
-
-	return 0;
+		return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
 }
 
 /* GPIO */
@@ -72,6 +75,34 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
 	st->gpio_write_state[GPIO_TUNER] = onoff;
 }
 
+static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask,
+				 u8 newval)
+{
+	u8 o[2], gpio_state;
+	int rc;
+
+	o[0] = 0xff & ~changemask;	/* mask of bits to keep */
+	o[1] = newval & changemask;	/* new values for bits  */
+
+	rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1);
+	if (rc < 0 || (gpio_state & changemask) != (newval & changemask))
+		deb_info("bluebird_gpio_write failed.\n");
+
+	return rc < 0 ? rc : gpio_state;
+}
+
+static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low)
+{
+	cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin);
+	msleep(5);
+	cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0);
+}
+
+static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
+{
+	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
+}
+
 /* I2C */
 static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 			  int num)
@@ -82,9 +113,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
-	if (num > 2)
-		warn("more than two i2c messages at a time is not handled yet. TODO.");
-
 	for (i = 0; i < num; i++) {
 
 		if (d->udev->descriptor.idVendor == USB_VID_MEDION)
@@ -97,8 +125,22 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 				break;
 			}
 
-		/* read request */
-		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+		if (msg[i].flags & I2C_M_RD) {
+			/* read only */
+			u8 obuf[3], ibuf[1+msg[i].len];
+			obuf[0] = 0;
+			obuf[1] = msg[i].len;
+			obuf[2] = msg[i].addr;
+			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
+					   obuf, 3,
+					   ibuf, 1+msg[i].len) < 0) {
+				warn("i2c read failed");
+				break;
+			}
+			memcpy(msg[i].buf, &ibuf[1], msg[i].len);
+		} else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) &&
+			   msg[i].addr == msg[i+1].addr) {
+			/* write to then read from same address */
 			u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
 			obuf[0] = msg[i].len;
 			obuf[1] = msg[i+1].len;
@@ -116,7 +158,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 			memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
 
 			i++;
-		} else { /* write */
+		} else {
+			/* write only */
 			u8 obuf[2+msg[i].len], ibuf;
 			obuf[0] = msg[i].addr;
 			obuf[1] = msg[i].len;
@@ -131,7 +174,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 	}
 
 	mutex_unlock(&d->i2c_mutex);
-	return i;
+	return i == num ? num : -EREMOTEIO;
 }
 
 static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
@@ -162,6 +205,17 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
 		return 0;
 }
 
+static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int rc = 0;
+
+	rc = cxusb_power_ctrl(d, onoff);
+	if (!onoff)
+		cxusb_nano2_led(d, 0);
+
+	return rc;
+}
+
 static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	u8 buf[2] = { 0x03, 0x00 };
@@ -197,6 +251,34 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 	return 0;
 }
 
+static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
+				    int *state)
+{
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	u8 ircode[4];
+	int i;
+	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
+			       .buf = ircode, .len = 4 };
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
+		return 0;
+
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (keymap[i].custom == ircode[1] &&
+		    keymap[i].data == ircode[2]) {
+			*event = keymap[i].event;
+			*state = REMOTE_KEY_PRESSED;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
 static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
 	{ 0xfe, 0x02, KEY_TV },
 	{ 0xfe, 0x0e, KEY_MP3 },
@@ -351,6 +433,20 @@ static struct mt352_config cxusb_mt352_config = {
 	.demod_init    = cxusb_mt352_demod_init,
 };
 
+static struct zl10353_config cxusb_zl10353_xc3028_config = {
+	.demod_address = 0x0f,
+	.if2 = 45600,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+};
+
+static struct mt352_config cxusb_mt352_xc3028_config = {
+	.demod_address = 0x0f,
+	.if2 = 4560,
+	.no_tuner = 1,
+	.demod_init = cxusb_mt352_demod_init,
+};
+
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -386,6 +482,51 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 	return 0;
 }
 
+static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
+{
+	struct dvb_usb_device *d = ptr;
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+		cxusb_bluebird_gpio_pulse(d, 0x01, 1);
+		break;
+	case XC2028_RESET_CLK:
+		deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+		break;
+	default:
+		deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__,
+			 command, arg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend	 *fe;
+	struct xc2028_config	  cfg = {
+		.i2c_adap  = &adap->dev->i2c_adap,
+		.i2c_addr  = 0x61,
+		.video_dev = adap->dev,
+		.callback  = dvico_bluebird_xc2028_callback,
+	};
+	static struct xc2028_ctrl ctl = {
+		.fname       = "xc3028-dvico-au-01.fw",
+		.max_len     = 64,
+		.scode_table = ZARLINK456,
+	};
+
+	fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
+	if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
+		return -EIO;
+
+	fe->ops.tuner_ops.set_config(fe, &ctl);
+
+	return 0;
+}
+
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	u8 b;
@@ -447,27 +588,120 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
 	return -EIO;
 }
 
+static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	u8 ircode[4];
+	int i;
+	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
+			       .buf = ircode, .len = 4 };
+
+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	/* reset the tuner and demodulator */
+	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+	if ((adap->fe = dvb_attach(zl10353_attach,
+				   &cxusb_zl10353_xc3028_config,
+				   &adap->dev->i2c_adap)) == NULL)
+		return -EIO;
+
+	/* try to determine if there is no IR decoder on the I2C bus */
+	for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) {
+		msleep(20);
+		if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
+			goto no_IR;
+		if (ircode[0] == 0 && ircode[1] == 0)
+			continue;
+		if (ircode[2] + ircode[3] != 0xff) {
+no_IR:
+			adap->dev->props.rc_key_map = NULL;
+			info("No IR receiver detected on this device.");
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	/* reset the tuner and demodulator */
+	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+	if ((adap->fe = dvb_attach(zl10353_attach,
+				   &cxusb_zl10353_xc3028_config,
+				   &adap->dev->i2c_adap)) != NULL)
+		return 0;
+
+	if ((adap->fe = dvb_attach(mt352_attach,
+				   &cxusb_mt352_xc3028_config,
+				   &adap->dev->i2c_adap)) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+/*
+ * DViCO has shipped two devices with the same USB ID, but only one of them
+ * needs a firmware download.  Check the device class details to see if they
+ * have non-default values to decide whether the device is actually cold or
+ * not, and forget a match if it turns out we selected the wrong device.
+ */
+static int bluebird_fx2_identify_state(struct usb_device *udev,
+				       struct dvb_usb_device_properties *props,
+				       struct dvb_usb_device_description **desc,
+				       int *cold)
+{
+	int wascold = *cold;
+
+	*cold = udev->descriptor.bDeviceClass == 0xff &&
+		udev->descriptor.bDeviceSubClass == 0xff &&
+		udev->descriptor.bDeviceProtocol == 0xff;
+
+	if (*cold && !wascold)
+		*desc = NULL;
+
+	return 0;
+}
+
 /*
  * DViCO bluebird firmware needs the "warm" product ID to be patched into the
  * firmware file before download.
  */
 
-#define BLUEBIRD_01_ID_OFFSET 6638
+static const int dvico_firmware_id_offsets[] = { 6638, 3204 };
 static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
 						  const struct firmware *fw)
 {
-	if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
-		return -EINVAL;
+	int pos;
+
+	for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) {
+		int idoff = dvico_firmware_id_offsets[pos];
 
-	if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
-	    fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
+		if (fw->size < idoff + 4)
+			continue;
 
-		fw->data[BLUEBIRD_01_ID_OFFSET + 2] =
-			le16_to_cpu(udev->descriptor.idProduct) + 1;
-		fw->data[BLUEBIRD_01_ID_OFFSET + 3] =
-			le16_to_cpu(udev->descriptor.idProduct) >> 8;
+		if (fw->data[idoff] == (USB_VID_DVICO & 0xff) &&
+		    fw->data[idoff + 1] == USB_VID_DVICO >> 8) {
+			fw->data[idoff + 2] =
+				le16_to_cpu(udev->descriptor.idProduct) + 1;
+			fw->data[idoff + 3] =
+				le16_to_cpu(udev->descriptor.idProduct) >> 8;
 
-		return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
+			return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
+		}
 	}
 
 	return -EINVAL;
@@ -479,6 +713,9 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
@@ -487,7 +724,10 @@ static int cxusb_probe(struct usb_interface *intf,
 		dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) {
+		dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_needsfirmware_properties,THIS_MODULE,NULL) == 0) {
 		return 0;
 	}
 
@@ -508,6 +748,9 @@ static struct usb_device_id cxusb_table [] = {
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
 	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -766,6 +1009,151 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
 	}
 };
 
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_dualdig4_frontend_attach,
+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = dvico_mce_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+	.rc_query         = cxusb_bluebird2_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T Dual Digital 4",
+			{ NULL },
+			{ &cxusb_table[13], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+	.identify_state   = bluebird_fx2_identify_state,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_nano2_frontend_attach,
+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_nano2_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = dvico_portable_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+	.rc_query         = cxusb_bluebird2_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T NANO2",
+			{ NULL },
+			{ &cxusb_table[14], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = DEVICE_SPECIFIC,
+	.firmware          = "dvb-usb-bluebird-02.fw",
+	.download_firmware = bluebird_patch_dvico_firmware_download,
+	.identify_state    = bluebird_fx2_identify_state,
+
+	.size_of_priv      = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_nano2_frontend_attach,
+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_nano2_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = dvico_portable_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+	.rc_query         = cxusb_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
+			{ &cxusb_table[14], NULL },
+			{ &cxusb_table[15], NULL },
+		},
+	}
+};
+
 static struct usb_driver cxusb_driver = {
 	.name		= "dvb_usb_cxusb",
 	.probe		= cxusb_probe,

+ 2 - 5
drivers/media/dvb/dvb-usb/cxusb.h

@@ -4,12 +4,9 @@
 #define DVB_USB_LOG_PREFIX "cxusb"
 #include "dvb-usb.h"
 
-extern int dvb_usb_cxusb_debug;
-#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
-#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
-				dprintk(dvb_usb_cxusb_debug,0x01,args)
-
 /* usb commands - some of it are guesses, don't have a reference yet */
+#define CMD_BLUEBIRD_GPIO_RW 0x05
+
 #define CMD_I2C_WRITE     0x08
 #define CMD_I2C_READ      0x09
 

+ 1 - 4
drivers/media/dvb/dvb-usb/dib0700_core.c

@@ -243,7 +243,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 	u8 b[4];
 
 	b[0] = REQUEST_ENABLE_VIDEO;
-	b[1] = 0x00;
+	b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
 	b[2] = (0x01 << 4); /* Master mode */
 	b[3] = 0x00;
 
@@ -256,9 +256,6 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
 	b[2] |= st->channel_state;
 
-	if (st->channel_state) /* if at least one channel is active */
-		b[1] = (0x01 << 4) | 0x00;
-
 	deb_info("data for streaming: %x %x\n",b[1],b[2]);
 
 	return dib0700_ctrl_wr(adap->dev, b, 4);

+ 139 - 10
drivers/media/dvb/dvb-usb/dib0700_devices.c

@@ -94,12 +94,28 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
 		(10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
 }
 
+static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = 0x50, .flags = 0,        .buf = &adrs, .len = 1 },
+		{ .addr = 0x50, .flags = I2C_M_RD, .buf = pval,  .len = 1 },
+	};
+	if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO;
+	return 0;
+}
+
 static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	struct dib0700_state *st = adap->dev->priv;
+	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
 	struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
-	return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id],
-		st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
+	s8 a;
+	int if1=1220;
+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
+		adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_500_2) {
+		if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
+	}
+	return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id],
+		if1) == NULL ? -ENODEV : 0;
 }
 
 /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
@@ -230,6 +246,27 @@ static struct mt2266_config stk7700d_mt2266_config[2] = {
 	}
 };
 
+static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (adap->id == 0) {
+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+		msleep(10);
+		dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config);
+	}
+
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
+				&stk7700d_dib7000p_mt2266_config[adap->id]);
+
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
 static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	if (adap->id == 0) {
@@ -415,6 +452,35 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
 	{ 0x1e, 0x38, KEY_YELLOW },
 	{ 0x1e, 0x3b, KEY_GOTO },
 	{ 0x1e, 0x3d, KEY_POWER },
+
+	/* Key codes for the Leadtek Winfast DTV Dongle */
+	{ 0x00, 0x42, KEY_POWER },
+	{ 0x07, 0x7c, KEY_TUNER },
+	{ 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */
+	{ 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/
+	{ 0x0f, 0x71, KEY_DOT }, /* frequency */
+	{ 0x07, 0x43, KEY_0 },
+	{ 0x0c, 0x41, KEY_1 },
+	{ 0x04, 0x43, KEY_2 },
+	{ 0x0b, 0x7f, KEY_3 },
+	{ 0x0e, 0x41, KEY_4 },
+	{ 0x06, 0x43, KEY_5 },
+	{ 0x09, 0x7f, KEY_6 },
+	{ 0x0d, 0x7e, KEY_7 },
+	{ 0x05, 0x7c, KEY_8 },
+	{ 0x0a, 0x40, KEY_9 },
+	{ 0x0e, 0x4e, KEY_CLEAR },
+	{ 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */
+	{ 0x0f, 0x41, KEY_LAST }, /* recall */
+	{ 0x03, 0x42, KEY_MUTE },
+	{ 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/
+	{ 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */
+	{ 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
+	{ 0x0b, 0x70, KEY_RECORD },
+	{ 0x03, 0x7d, KEY_VOLUMEUP },
+	{ 0x01, 0x7d, KEY_VOLUMEDOWN },
+	{ 0x02, 0x42, KEY_CHANNELUP },
+	{ 0x00, 0x7d, KEY_CHANNELDOWN },
 };
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
@@ -578,16 +644,22 @@ static struct mt2060_config stk7700p_mt2060_config = {
 
 static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
 {
+	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
 	struct dib0700_state *st = adap->dev->priv;
 	struct i2c_adapter *tun_i2c;
-
+	s8 a;
+	int if1=1220;
+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
+		adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_STICK) {
+		if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
+	}
 	if (st->is_dib7000pc)
 		tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 	else
 		tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 
 	return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
-		st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
+		if1) == NULL ? -ENODEV : 0;
 }
 
 /* DIB7070 generic */
@@ -709,6 +781,8 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
 	.agc_config_count = 1,
 	.agc = &dib7070_agc_config,
 	.bw  = &dib7070_bw_config_12_mhz,
+	.tuner_is_baseband = 1,
+	.spur_protect = 1,
 
 	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
 	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
@@ -748,6 +822,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
 		.agc_config_count = 1,
 		.agc = &dib7070_agc_config,
 		.bw  = &dib7070_bw_config_12_mhz,
+		.tuner_is_baseband = 1,
+		.spur_protect = 1,
 
 		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
 		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
@@ -760,6 +836,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
 		.agc_config_count = 1,
 		.agc = &dib7070_agc_config,
 		.bw  = &dib7070_bw_config_12_mhz,
+		.tuner_is_baseband = 1,
+		.spur_protect = 1,
 
 		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
 		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
@@ -821,6 +899,12 @@ struct usb_device_id dib0700_usb_id_table[] = {
 		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
 		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
 /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
+		{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U7000) },
+		{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
+		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000) },
+		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3100) },
+/* 25 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
+		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
 		{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -862,7 +946,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			},
 		},
 
-		.num_device_descs = 7,
+		.num_device_descs = 8,
 		.devices = {
 			{   "DiBcom STK7700P reference design",
 				{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
@@ -891,6 +975,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{   "AVerMedia AVerTV DVB-T Express",
 				{ &dib0700_usb_id_table[20] },
 				{ NULL },
+			},
+			{   "Gigabyte U7000",
+				{ &dib0700_usb_id_table[21], NULL },
+				{ NULL },
 			}
 		},
 
@@ -961,7 +1049,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{   "DiBcom STK7700D reference design",
 				{ &dib0700_usb_id_table[14], NULL },
 				{ NULL },
-			},
+			}
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
@@ -969,6 +1057,25 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
 		.rc_query         = dib0700_rc_query
 
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.frontend_attach  = stk7700P2_frontend_attach,
+				.tuner_attach     = stk7700d_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "ASUS My Cinema U3000 Mini DVBT Tuner",
+				{ &dib0700_usb_id_table[23], NULL },
+				{ NULL },
+			},
+		}
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 1,
@@ -983,7 +1090,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			},
 		},
 
-		.num_device_descs = 2,
+		.num_device_descs = 6,
 		.devices = {
 			{   "DiBcom STK7070P reference design",
 				{ &dib0700_usb_id_table[15], NULL },
@@ -993,7 +1100,29 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ &dib0700_usb_id_table[16], NULL },
 				{ NULL },
 			},
-		}
+			{   "Artec T14BR DVB-T",
+				{ &dib0700_usb_id_table[22], NULL },
+				{ NULL },
+			},
+			{   "ASUS My Cinema U3100 Mini DVBT Tuner",
+				{ &dib0700_usb_id_table[24], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-T Stick",
+				{ &dib0700_usb_id_table[25], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-T MyTV.t",
+				{ &dib0700_usb_id_table[26], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = dib0700_rc_keys,
+		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_query         = dib0700_rc_query
+
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 2,
@@ -1024,7 +1153,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
 				{ &dib0700_usb_id_table[18], NULL },
 				{ NULL },
-			},
+			}
 		}
 	},
 };

+ 2 - 1
drivers/media/dvb/dvb-usb/digitv.c

@@ -17,9 +17,10 @@
 #include "nxt6000.h"
 
 /* debug */
-int dvb_usb_digitv_debug;
+static int dvb_usb_digitv_debug;
 module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
 
 static int digitv_ctrl_msg(struct dvb_usb_device *d,
 		u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)

+ 0 - 3
drivers/media/dvb/dvb-usb/digitv.h

@@ -8,9 +8,6 @@ struct digitv_state {
     int is_nxt6000;
 };
 
-extern int dvb_usb_digitv_debug;
-#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
-
 /* protocol (from usblogging and the SDK:
  *
  * Always 7 bytes bulk message(s) for controlling

+ 17 - 1
drivers/media/dvb/dvb-usb/dvb-usb-ids.h

@@ -15,7 +15,9 @@
 #define USB_VID_ALCOR_MICRO			0x058f
 #define USB_VID_ALINK				0x05e3
 #define USB_VID_ANCHOR				0x0547
+#define USB_VID_ANSONIC				0x10b9
 #define USB_VID_ANUBIS_ELECTRONIC		0x10fd
+#define USB_VID_ASUS				0x0b05
 #define USB_VID_AVERMEDIA			0x07ca
 #define USB_VID_COMPRO				0x185b
 #define USB_VID_COMPRO_UNK			0x145f
@@ -44,12 +46,16 @@
 #define USB_VID_ULTIMA_ELECTRONIC		0x05d8
 #define USB_VID_UNIWILL				0x1584
 #define USB_VID_WIDEVIEW			0x14aa
+/* dom : pour gigabyte u7000 */
+#define USB_VID_GIGABYTE			0x1044
+
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
 #define USB_PID_ADSTECH_USB2_WARM			0xa334
 #define USB_PID_AFATECH_AF9005				0x9020
 #define USB_VID_ALINK_DTU				0xf170
+#define USB_PID_ANSONIC_DVBT_USB			0x6000
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
@@ -69,6 +75,7 @@
 #define USB_PID_DIBCOM_STK7700P				0x1e14
 #define USB_PID_DIBCOM_STK7700P_PC			0x1e78
 #define USB_PID_DIBCOM_STK7700D				0x1ef0
+#define USB_PID_DIBCOM_STK7700_U7000			0x7001
 #define USB_PID_DIBCOM_STK7070P				0x1ebc
 #define USB_PID_DIBCOM_STK7070PD			0x1ebe
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
@@ -99,6 +106,7 @@
 #define USB_PID_ULTIMA_TVBOX_USB2_WARM			0x810a
 #define USB_PID_ARTEC_T14_COLD				0x810b
 #define USB_PID_ARTEC_T14_WARM				0x810c
+#define USB_PID_ARTEC_T14BR				0x810f
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD		0x8613
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM		0x1002
 #define USB_PID_UNK_HYPER_PALTEK_COLD			0x005e
@@ -120,6 +128,8 @@
 #define USB_PID_HAUPPAUGE_NOVA_T_500_2			0x9950
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK			0x7050
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2		0x7060
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
+#define USB_PID_HAUPPAUGE_MYTV_T			0x7080
 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
 #define USB_PID_AVERMEDIA_EXPRESS			0xb568
 #define USB_PID_AVERMEDIA_VOLAR				0xa807
@@ -143,6 +153,9 @@
 #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM		0xdb51
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD		0xdb58
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM		0xdb59
+#define USB_PID_DVICO_BLUEBIRD_DUAL_4			0xdb78
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2		0xdb70
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM	0xdb71
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD		0xdb54
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM		0xdb55
 #define USB_PID_MEDION_MD95700				0x0932
@@ -170,6 +183,9 @@
 #define USB_PID_OPERA1_WARM				0x3829
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD		0x0514
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM		0x0513
-
+/* dom pour gigabyte u7000 */
+#define USB_PID_GIGABYTE_U7000				0x7001
+#define USB_PID_ASUS_U3000				0x171f
+#define USB_PID_ASUS_U3100				0x173f
 
 #endif

+ 3 - 3
drivers/media/dvb/dvb-usb/gl861.c

@@ -56,12 +56,12 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
 	if (num > 2)
 		return -EINVAL;
 
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
 	for (i = 0; i < num; i++) {
 		/* write/read request */
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {

+ 0 - 16
drivers/media/dvb/dvb-usb/gp8psk.c

@@ -171,22 +171,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
 	return 0;
 }
 
-int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
-{
-	u8 buf;
-	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
-	/* Turn off 8psk power */
-	if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
-		return -EINVAL;
-	/* Turn On 8psk power */
-	if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
-		return -EINVAL;
-	/* load BCM4500 firmware */
-	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
-		if (gp8psk_load_bcm4500fw(d))
-			return EINVAL;
-	return 0;
-}
 
 static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {

+ 0 - 1
drivers/media/dvb/dvb-usb/gp8psk.h

@@ -92,6 +92,5 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
 extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
 extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
 			     u16 index, u8 *b, int blen);
-extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
 
 #endif

+ 4 - 2
drivers/media/dvb/dvb-usb/opera1.c

@@ -10,7 +10,9 @@
 * see Documentation/dvb/README.dvb-usb for more information
 */
 
-#include "opera1.h"
+#define DVB_USB_LOG_PREFIX "opera"
+
+#include "dvb-usb.h"
 #include "stv0299.h"
 
 #define OPERA_READ_MSG 0
@@ -38,7 +40,7 @@ struct opera_rc_keys {
 	u32 event;
 };
 
-int dvb_usb_opera1_debug;
+static int dvb_usb_opera1_debug;
 module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
 MODULE_PARM_DESC(debug,
 		 "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."

+ 0 - 9
drivers/media/dvb/dvb-usb/opera1.h

@@ -1,9 +0,0 @@
-#ifndef _OPERA1_H_
-#define _OPERA1_H_
-
-#define DVB_USB_LOG_PREFIX "opera"
-#include "dvb-usb.h"
-
-extern int dvb_usb_opera1_debug;
-#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args)
-#endif

+ 1 - 14
drivers/media/dvb/dvb-usb/vp702x.c

@@ -56,7 +56,7 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
 	return ret;
 }
 
-int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
 			     u16 index, u8 *b, int blen)
 {
 	int ret;
@@ -204,19 +204,6 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 	return 0;
 }
 
-int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	struct vp702x_device_state *st = d->priv;
-
-	if (st->power_state == 0 && onoff)
-		vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
-	else if (st->power_state == 1 && onoff == 0)
-		vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
-
-	st->power_state = onoff;
-
-	return 0;
-}
 
 static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
 {

+ 0 - 2
drivers/media/dvb/dvb-usb/vp702x.h

@@ -102,7 +102,5 @@ 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);
 extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
-extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
-extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff);
 
 #endif

+ 4 - 1
drivers/media/dvb/dvb-usb/vp7045.c

@@ -15,9 +15,12 @@
 #include "vp7045.h"
 
 /* debug */
-int dvb_usb_vp7045_debug;
+static int dvb_usb_vp7045_debug;
 module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
 
 int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
 {

+ 0 - 5
drivers/media/dvb/dvb-usb/vp7045.h

@@ -17,11 +17,6 @@
 #define DVB_USB_LOG_PREFIX "vp7045"
 #include "dvb-usb.h"
 
-extern int dvb_usb_vp7045_debug;
-#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
-#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
-#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
-
 /* vp7045 commands */
 
 /* Twinhan Vendor requests */

+ 16 - 0
drivers/media/dvb/frontends/Kconfig

@@ -316,6 +316,13 @@ config DVB_TDA827X
 	help
 	  A DVB-T silicon tuner module. Say Y when you want to support this tuner.
 
+config DVB_TDA18271
+	tristate "NXP TDA18271 silicon tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A silicon tuner module. Say Y when you want to support this tuner.
+
 config DVB_TUNER_QT1010
 	tristate "Quantek QT1010 silicon tuner"
 	depends on DVB_CORE && I2C
@@ -353,6 +360,15 @@ config DVB_TUNER_DIB0070
 	  This device is only used inside a SiP called togther with a
 	  demodulator for now.
 
+config DVB_TUNER_XC5000
+	tristate "Xceive XC5000 silicon tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon tuner XC5000 from Xceive.
+	  This device is only used inside a SiP called togther with a
+	  demodulator for now.
+
 comment "Miscellaneous devices"
 	depends on DVB_CORE
 

+ 5 - 0
drivers/media/dvb/frontends/Makefile

@@ -3,6 +3,9 @@
 #
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/video/
+
+tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -39,6 +42,7 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
 obj-$(CONFIG_DVB_TDA827X) += tda827x.o
+obj-$(CONFIG_DVB_TDA18271) += tda18271.o
 obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
 obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
 obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
@@ -46,3 +50,4 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
 obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
+obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o

+ 11 - 2
drivers/media/dvb/frontends/dib0070.c

@@ -434,9 +434,14 @@ static u16 dib0070_p1f_defaults[] =
 	0,
 };
 
-static void dib0070_wbd_calibration(struct dib0070_state *state)
+static void dib0070_wbd_calibration(struct dvb_frontend *fe)
 {
 	u16 wbd_offs;
+	struct dib0070_state *state = fe->tuner_priv;
+
+	if (state->cfg->sleep)
+		state->cfg->sleep(fe, 0);
+
 	dib0070_write_reg(state, 0x0f, 0x6d81);
 	dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
 	msleep(9);
@@ -444,6 +449,10 @@ static void dib0070_wbd_calibration(struct dib0070_state *state)
 	dib0070_write_reg(state, 0x20, 0);
 	state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
 	dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
+
+	if (state->cfg->sleep)
+		state->cfg->sleep(fe, 1);
+
 }
 
 u16 dib0070_wbd_offset(struct dvb_frontend *fe)
@@ -560,7 +569,7 @@ struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
 	if (dib0070_reset(state) != 0)
 		goto free_mem;
 
-	dib0070_wbd_calibration(state);
+	dib0070_wbd_calibration(fe);
 
 	printk(KERN_INFO "DiB0070: successfully identified\n");
 	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));

+ 7 - 3
drivers/media/dvb/frontends/dib3000mc.c

@@ -684,6 +684,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib3000mc_state *state = fe->demodulator_priv;
+    int ret;
+
+	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
 
 	state->current_bandwidth = fep->u.ofdm.bandwidth;
 	dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
@@ -700,7 +703,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 		fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
 		fep->u.ofdm.constellation     == QAM_AUTO ||
 		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
-		int i = 100, found;
+		int i = 1000, found;
 
 		dib3000mc_autosearch_start(fe, fep);
 		do {
@@ -715,10 +718,11 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 		dib3000mc_get_frontend(fe, fep);
 	}
 
+    ret = dib3000mc_tune(fe, fep);
+
 	/* make this a config parameter */
 	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-
-	return dib3000mc_tune(fe, fep);
+    return ret;
 }
 
 static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)

+ 6 - 3
drivers/media/dvb/frontends/dib7000m.c

@@ -1171,7 +1171,9 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib7000m_state *state = fe->demodulator_priv;
-	int time;
+	int time, ret;
+
+    dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
 
 	state->current_bandwidth = fep->u.ofdm.bandwidth;
 	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
@@ -1206,10 +1208,11 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
 		dib7000m_get_frontend(fe, fep);
 	}
 
+	ret = dib7000m_tune(fe, fep);
+
 	/* make this a config parameter */
 	dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-
-	return dib7000m_tune(fe, fep);
+	return ret;
 }
 
 static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)

+ 9 - 9
drivers/media/dvb/frontends/dib7000p.c

@@ -35,8 +35,8 @@ struct dib7000p_state {
 
 	u16 wbd_ref;
 
-	u8 current_band;
-	fe_bandwidth_t current_bandwidth;
+	u8  current_band;
+	u32 current_bandwidth;
 	struct dibx000_agc_config *current_agc;
 	u32 timf;
 
@@ -1074,7 +1074,7 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe,
 
 	fep->inversion = INVERSION_AUTO;
 
-	fep->u.ofdm.bandwidth = state->current_bandwidth;
+	fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
 
 	switch ((tps >> 8) & 0x3) {
 		case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
@@ -1128,12 +1128,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
-	int time;
+	int time, ret;
 
-	state->current_bandwidth = fep->u.ofdm.bandwidth;
-	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+	dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
 
-	/* maybe the parameter has been changed */
+    /* maybe the parameter has been changed */
 	state->sfn_workaround_active = buggy_sfn_workaround;
 
 	if (fe->ops.tuner_ops.set_params)
@@ -1166,10 +1165,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
 		dib7000p_get_frontend(fe, fep);
 	}
 
+	ret = dib7000p_tune(fe, fep);
+
 	/* make this a config parameter */
 	dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-
-	return dib7000p_tune(fe, fep);
+    return ret;
 }
 
 static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)

+ 5 - 0
drivers/media/dvb/frontends/dibx000_common.h

@@ -128,6 +128,11 @@ enum dibx000_adc_states {
 			     (v) == BANDWIDTH_7_MHZ  ? 7000 : \
 			     (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000 )
 
+#define BANDWIDTH_TO_INDEX(v) ( \
+	(v) == 8000 ? BANDWIDTH_8_MHZ : \
+		(v) == 7000 ? BANDWIDTH_7_MHZ : \
+		(v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ )
+
 /* Chip output mode. */
 #define OUTMODE_HIGH_Z              0
 #define OUTMODE_MPEG2_PAR_GATED_CLK 1

+ 134 - 70
drivers/media/dvb/frontends/mt2266.c

@@ -38,8 +38,12 @@ struct mt2266_priv {
 
 	u32 frequency;
 	u32 bandwidth;
+	u8 band;
 };
 
+#define MT2266_VHF 1
+#define MT2266_UHF 0
+
 /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
 
 static int debug;
@@ -90,26 +94,30 @@ static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
 }
 
 // Initialisation sequences
-static u8 mt2266_init1[] = {
-	REG_TUNE,
-	0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f };
+static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
+				 0x00, 0x52, 0x99, 0x3f };
 
 static u8 mt2266_init2[] = {
-	0x17,                                     0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a,
-	0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01,
-	0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d };
+    0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
+    0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
+    0xff, 0x00, 0x77, 0x0f, 0x2d
+};
+
+static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
+						0x22, 0x22, 0x22, 0x22 };
 
-static u8 mt2266_init_8mhz[] = {
-	REG_BANDWIDTH,
-	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
+static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
+						0x32, 0x32, 0x32, 0x32 };
 
-static u8 mt2266_init_7mhz[] = {
-	REG_BANDWIDTH,
-	0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
+static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
+						0xa7, 0xa7, 0xa7, 0xa7 };
 
-static u8 mt2266_init_6mhz[] = {
-	REG_BANDWIDTH,
-	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 };
+static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
+			   0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
+
+static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
+			   0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
 
 #define FREF 30000       // Quartz oscillator 30 MHz
 
@@ -122,35 +130,78 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
 	u8  lnaband;
 	u8  b[10];
 	int i;
+	u8 band;
 
 	priv = fe->tuner_priv;
 
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0xff);
-
 	freq = params->frequency / 1000; // Hz -> kHz
+	if (freq < 470000 && freq > 230000)
+		return -EINVAL; /* Gap between VHF and UHF bands */
 	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 	priv->frequency = freq * 1000;
-	tune=2 * freq * (8192/16) / (FREF/16);
-
-	if (freq <= 495000) lnaband = 0xEE; else
-	if (freq <= 525000) lnaband = 0xDD; else
-	if (freq <= 550000) lnaband = 0xCC; else
-	if (freq <= 580000) lnaband = 0xBB; else
-	if (freq <= 605000) lnaband = 0xAA; else
-	if (freq <= 630000) lnaband = 0x99; else
-	if (freq <= 655000) lnaband = 0x88; else
-	if (freq <= 685000) lnaband = 0x77; else
-	if (freq <= 710000) lnaband = 0x66; else
-	if (freq <= 735000) lnaband = 0x55; else
-	if (freq <= 765000) lnaband = 0x44; else
-	if (freq <= 802000) lnaband = 0x33; else
-	if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11;
-
-	msleep(100);
-	mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz:
-				(params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz:
-				mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+
+	tune = 2 * freq * (8192/16) / (FREF/16);
+	band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
+	if (band == MT2266_VHF)
+		tune *= 2;
+
+	switch (params->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		mt2266_writeregs(priv, mt2266_init_6mhz,
+				 sizeof(mt2266_init_6mhz));
+		break;
+	case BANDWIDTH_7_MHZ:
+		mt2266_writeregs(priv, mt2266_init_7mhz,
+				 sizeof(mt2266_init_7mhz));
+		break;
+	case BANDWIDTH_8_MHZ:
+	default:
+		mt2266_writeregs(priv, mt2266_init_8mhz,
+				 sizeof(mt2266_init_8mhz));
+		break;
+	}
+
+	if (band == MT2266_VHF && priv->band == MT2266_UHF) {
+		dprintk("Switch from UHF to VHF");
+		mt2266_writereg(priv, 0x05, 0x04);
+		mt2266_writereg(priv, 0x19, 0x61);
+		mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
+	} else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
+		dprintk("Switch from VHF to UHF");
+		mt2266_writereg(priv, 0x05, 0x52);
+		mt2266_writereg(priv, 0x19, 0x61);
+		mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
+	}
+	msleep(10);
+
+	if (freq <= 495000)
+		lnaband = 0xEE;
+	else if (freq <= 525000)
+		lnaband = 0xDD;
+	else if (freq <= 550000)
+		lnaband = 0xCC;
+	else if (freq <= 580000)
+		lnaband = 0xBB;
+	else if (freq <= 605000)
+		lnaband = 0xAA;
+	else if (freq <= 630000)
+		lnaband = 0x99;
+	else if (freq <= 655000)
+		lnaband = 0x88;
+	else if (freq <= 685000)
+		lnaband = 0x77;
+	else if (freq <= 710000)
+		lnaband = 0x66;
+	else if (freq <= 735000)
+		lnaband = 0x55;
+	else if (freq <= 765000)
+		lnaband = 0x44;
+	else if (freq <= 802000)
+		lnaband = 0x33;
+	else if (freq <= 840000)
+		lnaband = 0x22;
+	else
+		lnaband = 0x11;
 
 	b[0] = REG_TUNE;
 	b[1] = (tune >> 8) & 0x1F;
@@ -158,47 +209,54 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
 	b[3] = tune >> 13;
 	mt2266_writeregs(priv,b,4);
 
-	dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband);
-	dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]);
-
-	b[0] = 0x05;
-	b[1] = 0x62;
-	b[2] = lnaband;
-	mt2266_writeregs(priv,b,3);
+	dprintk("set_parms: tune=%d band=%d %s",
+		(int) tune, (int) lnaband,
+		(band == MT2266_UHF) ? "UHF" : "VHF");
+	dprintk("set_parms: [1..3]: %2x %2x %2x",
+		(int) b[1], (int) b[2], (int)b[3]);
+
+	if (band == MT2266_UHF) {
+		b[0] = 0x05;
+		b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
+		b[2] = lnaband;
+		mt2266_writeregs(priv, b, 3);
+	}
 
-	//Waits for pll lock or timeout
+	/* Wait for pll lock or timeout */
 	i = 0;
 	do {
 		mt2266_readreg(priv,REG_LOCK,b);
-		if ((b[0] & 0x40)==0x40)
+		if (b[0] & 0x40)
 			break;
 		msleep(10);
 		i++;
 	} while (i<10);
 	dprintk("Lock when i=%i",(int)i);
+
+	if (band == MT2266_UHF && priv->band == MT2266_VHF)
+		mt2266_writereg(priv, 0x05, 0x62);
+
+	priv->band = band;
+
 	return ret;
 }
 
 static void mt2266_calibrate(struct mt2266_priv *priv)
 {
-	mt2266_writereg(priv,0x11,0x03);
-	mt2266_writereg(priv,0x11,0x01);
-
-	mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1));
-	mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2));
-
-	mt2266_writereg(priv,0x33,0x5e);
-	mt2266_writereg(priv,0x10,0x10);
-	mt2266_writereg(priv,0x10,0x00);
-
-	mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
-
+	mt2266_writereg(priv, 0x11, 0x03);
+	mt2266_writereg(priv, 0x11, 0x01);
+	mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
+	mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
+	mt2266_writereg(priv, 0x33, 0x5e);
+	mt2266_writereg(priv, 0x10, 0x10);
+	mt2266_writereg(priv, 0x10, 0x00);
+	mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
 	msleep(25);
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0x00);
+	mt2266_writereg(priv, 0x17, 0x6d);
+	mt2266_writereg(priv, 0x1c, 0x00);
 	msleep(75);
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0xff);
+	mt2266_writereg(priv, 0x17, 0x6d);
+	mt2266_writereg(priv, 0x1c, 0xff);
 }
 
 static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
@@ -217,17 +275,22 @@ static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 
 static int mt2266_init(struct dvb_frontend *fe)
 {
+	int ret;
 	struct mt2266_priv *priv = fe->tuner_priv;
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0xff);
+	ret = mt2266_writereg(priv, 0x17, 0x6d);
+	if (ret < 0)
+		return ret;
+	ret = mt2266_writereg(priv, 0x1c, 0xff);
+	if (ret < 0)
+		return ret;
 	return 0;
 }
 
 static int mt2266_sleep(struct dvb_frontend *fe)
 {
 	struct mt2266_priv *priv = fe->tuner_priv;
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0x00);
+	mt2266_writereg(priv, 0x17, 0x6d);
+	mt2266_writereg(priv, 0x1c, 0x00);
 	return 0;
 }
 
@@ -241,8 +304,8 @@ static int mt2266_release(struct dvb_frontend *fe)
 static const struct dvb_tuner_ops mt2266_tuner_ops = {
 	.info = {
 		.name           = "Microtune MT2266",
-		.frequency_min  = 470000000,
-		.frequency_max  = 860000000,
+		.frequency_min  = 174000000,
+		.frequency_max  = 862000000,
 		.frequency_step =     50000,
 	},
 	.release       = mt2266_release,
@@ -264,8 +327,9 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter
 
 	priv->cfg      = cfg;
 	priv->i2c      = i2c;
+	priv->band     = MT2266_UHF;
 
-	if (mt2266_readreg(priv,0,&id) != 0) {
+	if (mt2266_readreg(priv, 0, &id)) {
 		kfree(priv);
 		return NULL;
 	}

+ 152 - 105
drivers/media/dvb/frontends/mt312.c

@@ -37,9 +37,9 @@
 
 
 struct mt312_state {
-	struct i2c_adapter* i2c;
+	struct i2c_adapter *i2c;
 	/* configuration settings */
-	const struct mt312_config* config;
+	const struct mt312_config *config;
 	struct dvb_frontend frontend;
 
 	u8 id;
@@ -49,14 +49,15 @@ struct mt312_state {
 static int debug;
 #define dprintk(args...) \
 	do { \
-		if (debug) printk(KERN_DEBUG "mt312: " args); \
+		if (debug) \
+			printk(KERN_DEBUG "mt312: " args); \
 	} while (0)
 
 #define MT312_SYS_CLK		90000000UL	/* 90 MHz */
 #define MT312_LPOWER_SYS_CLK	60000000UL	/* 60 MHz */
 #define MT312_PLL_CLK		10000000UL	/* 10 MHz */
 
-static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
+static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
 		      void *buf, const size_t count)
 {
 	int ret;
@@ -79,7 +80,7 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
 		return -EREMOTEIO;
 	}
 
-	if(debug) {
+	if (debug) {
 		int i;
 		dprintk("R(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
@@ -90,14 +91,14 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
 	return 0;
 }
 
-static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
+static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
 		       const void *src, const size_t count)
 {
 	int ret;
 	u8 buf[count + 1];
 	struct i2c_msg msg;
 
-	if(debug) {
+	if (debug) {
 		int i;
 		dprintk("W(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
@@ -123,13 +124,13 @@ static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
 	return 0;
 }
 
-static inline int mt312_readreg(struct mt312_state* state,
+static inline int mt312_readreg(struct mt312_state *state,
 				const enum mt312_reg_addr reg, u8 *val)
 {
 	return mt312_read(state, reg, val, 1);
 }
 
-static inline int mt312_writereg(struct mt312_state* state,
+static inline int mt312_writereg(struct mt312_state *state,
 				 const enum mt312_reg_addr reg, const u8 val)
 {
 	return mt312_write(state, reg, &val, 1);
@@ -140,18 +141,19 @@ static inline u32 mt312_div(u32 a, u32 b)
 	return (a + (b / 2)) / b;
 }
 
-static int mt312_reset(struct mt312_state* state, const u8 full)
+static int mt312_reset(struct mt312_state *state, const u8 full)
 {
 	return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
 }
 
-static int mt312_get_inversion(struct mt312_state* state,
+static int mt312_get_inversion(struct mt312_state *state,
 			       fe_spectral_inversion_t *i)
 {
 	int ret;
 	u8 vit_mode;
 
-	if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0)
+	ret = mt312_readreg(state, VIT_MODE, &vit_mode);
+	if (ret < 0)
 		return ret;
 
 	if (vit_mode & 0x80)	/* auto inversion was used */
@@ -160,7 +162,7 @@ static int mt312_get_inversion(struct mt312_state* state,
 	return 0;
 }
 
-static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
+static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
 {
 	int ret;
 	u8 sym_rate_h;
@@ -169,37 +171,44 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
 	u16 monitor;
 	u8 buf[2];
 
-	if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0)
+	ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h);
+	if (ret < 0)
 		return ret;
 
-	if (sym_rate_h & 0x80) {	/* symbol rate search was used */
-		if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0)
+	if (sym_rate_h & 0x80) {
+		/* symbol rate search was used */
+		ret = mt312_writereg(state, MON_CTRL, 0x03);
+		if (ret < 0)
 			return ret;
 
-		if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
+		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
+		if (ret < 0)
 			return ret;
 
 		monitor = (buf[0] << 8) | buf[1];
 
-		dprintk(KERN_DEBUG "sr(auto) = %u\n",
+		dprintk("sr(auto) = %u\n",
 		       mt312_div(monitor * 15625, 4));
 	} else {
-		if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0)
+		ret = mt312_writereg(state, MON_CTRL, 0x05);
+		if (ret < 0)
 			return ret;
 
-		if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
+		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
+		if (ret < 0)
 			return ret;
 
 		dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
 
-		if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
+		ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf));
+		if (ret < 0)
 			return ret;
 
 		sym_rat_op = (buf[0] << 8) | buf[1];
 
-		dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
+		dprintk("sym_rat_op=%d dec_ratio=%d\n",
 		       sym_rat_op, dec_ratio);
-		dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
+		dprintk("*sr(manual) = %lu\n",
 		       (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
 			2) - dec_ratio);
 	}
@@ -207,7 +216,7 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
 	return 0;
 }
 
-static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
+static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr)
 {
 	const fe_code_rate_t fec_tab[8] =
 	    { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
@@ -216,7 +225,8 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
 	int ret;
 	u8 fec_status;
 
-	if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0)
+	ret = mt312_readreg(state, FEC_STATUS, &fec_status);
+	if (ret < 0)
 		return ret;
 
 	*cr = fec_tab[(fec_status >> 4) & 0x07];
@@ -224,61 +234,72 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
 	return 0;
 }
 
-static int mt312_initfe(struct dvb_frontend* fe)
+static int mt312_initfe(struct dvb_frontend *fe)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[2];
 
 	/* wake up */
-	if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0)
+	ret = mt312_writereg(state, CONFIG,
+			(state->frequency == 60 ? 0x88 : 0x8c));
+	if (ret < 0)
 		return ret;
 
 	/* wait at least 150 usec */
 	udelay(150);
 
 	/* full reset */
-	if ((ret = mt312_reset(state, 1)) < 0)
+	ret = mt312_reset(state, 1);
+	if (ret < 0)
 		return ret;
 
-// Per datasheet, write correct values. 09/28/03 ACCJr.
-// If we don't do this, we won't get FE_HAS_VITERBI in the VP310.
+/* Per datasheet, write correct values. 09/28/03 ACCJr.
+ * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */
 	{
-		u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00};
+		u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02,
+				  0x01, 0x00, 0x00, 0x00 };
 
-		if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0)
+		ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def));
+		if (ret < 0)
 			return ret;
 	}
 
 	/* SYS_CLK */
-	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000);
+	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK :
+				MT312_SYS_CLK) * 2, 1000000);
 
 	/* DISEQC_RATIO */
 	buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
 
-	if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0)
+	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0)
+	ret = mt312_writereg(state, SNR_THS_HIGH, 0x32);
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0)
+	ret = mt312_writereg(state, OP_CTRL, 0x53);
+	if (ret < 0)
 		return ret;
 
 	/* TS_SW_LIM */
 	buf[0] = 0x8c;
 	buf[1] = 0x98;
 
-	if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
+	ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
+	ret = mt312_writereg(state, CS_SW_LIM, 0x69);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_send_master_cmd(struct dvb_frontend* fe,
+static int mt312_send_master_cmd(struct dvb_frontend *fe,
 				 struct dvb_diseqc_master_cmd *c)
 {
 	struct mt312_state *state = fe->demodulator_priv;
@@ -288,29 +309,31 @@ static int mt312_send_master_cmd(struct dvb_frontend* fe,
 	if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
 		return -EINVAL;
 
-	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0)
 		return ret;
 
-	if ((ret =
-	     mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
+	ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
+	if (ret < 0)
 		return ret;
 
-	if ((ret =
-	     mt312_writereg(state, DISEQC_MODE,
-			    (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
-			    | 0x04)) < 0)
+	ret = mt312_writereg(state, DISEQC_MODE,
+			     (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
+			     | 0x04);
+	if (ret < 0)
 		return ret;
 
 	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
-	if (c->msg[0] & 0x02)
-		if ((ret =
-		     mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
+	if (c->msg[0] & 0x02) {
+		ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
+		if (ret < 0)
 			return ret;
+	}
 
 	return 0;
 }
 
-static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
+static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	const u8 mini_tab[2] = { 0x02, 0x03 };
@@ -321,18 +344,19 @@ static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
 	if (c > SEC_MINI_B)
 		return -EINVAL;
 
-	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0)
 		return ret;
 
-	if ((ret =
-	     mt312_writereg(state, DISEQC_MODE,
-			    (diseqc_mode & 0x40) | mini_tab[c])) < 0)
+	ret = mt312_writereg(state, DISEQC_MODE,
+			     (diseqc_mode & 0x40) | mini_tab[c]);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
+static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	const u8 tone_tab[2] = { 0x01, 0x00 };
@@ -343,18 +367,19 @@ static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
 	if (t > SEC_TONE_OFF)
 		return -EINVAL;
 
-	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0)
 		return ret;
 
-	if ((ret =
-	     mt312_writereg(state, DISEQC_MODE,
-			    (diseqc_mode & 0x40) | tone_tab[t])) < 0)
+	ret = mt312_writereg(state, DISEQC_MODE,
+			     (diseqc_mode & 0x40) | tone_tab[t]);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
+static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
@@ -365,7 +390,7 @@ static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
 	return mt312_writereg(state, DISEQC_MODE, volt_tab[v]);
 }
 
-static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
+static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
@@ -373,10 +398,12 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
 
 	*s = 0;
 
-	if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0)
+	ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status));
+	if (ret < 0)
 		return ret;
 
-	dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
+	dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x,"
+		" FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
 
 	if (status[0] & 0xc0)
 		*s |= FE_HAS_SIGNAL;	/* signal noise ratio */
@@ -392,13 +419,14 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
 	return 0;
 }
 
-static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
+static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[3];
 
-	if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0)
+	ret = mt312_read(state, RS_BERCNT_H, buf, 3);
+	if (ret < 0)
 		return ret;
 
 	*ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
@@ -406,7 +434,8 @@ static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
 	return 0;
 }
 
-static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength)
+static int mt312_read_signal_strength(struct dvb_frontend *fe,
+				      u16 *signal_strength)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
@@ -414,7 +443,8 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
 	u16 agc;
 	s16 err_db;
 
-	if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0)
+	ret = mt312_read(state, AGC_H, buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
 	agc = (buf[0] << 6) | (buf[1] >> 2);
@@ -422,18 +452,19 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
 
 	*signal_strength = agc;
 
-	dprintk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db);
+	dprintk("agc=%08x err_db=%hd\n", agc, err_db);
 
 	return 0;
 }
 
-static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
+static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[2];
 
-	if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0)
+	ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
 	*snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
@@ -441,13 +472,14 @@ static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
 	return 0;
 }
 
-static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
+static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[2];
 
-	if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0)
+	ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
 	*ubc = (buf[0] << 8) | buf[1];
@@ -455,7 +487,7 @@ static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
 	return 0;
 }
 
-static int mt312_set_frontend(struct dvb_frontend* fe,
+static int mt312_set_frontend(struct dvb_frontend *fe,
 			      struct dvb_frontend_parameters *p)
 {
 	struct mt312_state *state = fe->demodulator_priv;
@@ -491,24 +523,28 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 
 	switch (state->id) {
 	case ID_VP310:
-	// For now we will do this only for the VP310.
-	// It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
+	/* For now we will do this only for the VP310.
+	 * It should be better for the mt312 as well,
+	 * but tuning will be slower. ACCJr 09/29/03
+	 */
 		ret = mt312_readreg(state, CONFIG, &config_val);
 		if (ret < 0)
 			return ret;
-		if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
-		{
-			if ((config_val & 0x0c) == 0x08) { //We are running 60MHz
+		if (p->u.qpsk.symbol_rate >= 30000000) {
+			/* Note that 30MS/s should use 90MHz */
+			if ((config_val & 0x0c) == 0x08) {
+				/* We are running 60MHz */
 				state->frequency = 90;
-				if ((ret = mt312_initfe(fe)) < 0)
+				ret = mt312_initfe(fe);
+				if (ret < 0)
 					return ret;
 			}
-		}
-		else
-		{
-			if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz
+		} else {
+			if ((config_val & 0x0c) == 0x0C) {
+				/* We are running 90MHz */
 				state->frequency = 60;
-				if ((ret = mt312_initfe(fe)) < 0)
+				ret = mt312_initfe(fe);
+				if (ret < 0)
 					return ret;
 			}
 		}
@@ -523,7 +559,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 
 	if (fe->ops.tuner_ops.set_params) {
 		fe->ops.tuner_ops.set_params(fe, p);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
 	}
 
 	/* sr = (u16)(sr * 256.0 / 1000000.0) */
@@ -545,7 +582,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 	/* GO */
 	buf[4] = 0x01;
 
-	if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0)
+	ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
 	mt312_reset(state, 0);
@@ -553,27 +591,30 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 	return 0;
 }
 
-static int mt312_get_frontend(struct dvb_frontend* fe,
+static int mt312_get_frontend(struct dvb_frontend *fe,
 			      struct dvb_frontend_parameters *p)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 
-	if ((ret = mt312_get_inversion(state, &p->inversion)) < 0)
+	ret = mt312_get_inversion(state, &p->inversion);
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0)
+	ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate);
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0)
+	ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
-	struct mt312_state* state = fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 
 	if (enable) {
 		return mt312_writereg(state, GPP_CTRL, 0x40);
@@ -582,27 +623,31 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
 	}
 }
 
-static int mt312_sleep(struct dvb_frontend* fe)
+static int mt312_sleep(struct dvb_frontend *fe)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 config;
 
 	/* reset all registers to defaults */
-	if ((ret = mt312_reset(state, 1)) < 0)
+	ret = mt312_reset(state, 1);
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_readreg(state, CONFIG, &config)) < 0)
+	ret = mt312_readreg(state, CONFIG, &config);
+	if (ret < 0)
 		return ret;
 
 	/* enter standby */
-	if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0)
+	ret = mt312_writereg(state, CONFIG, config & 0x7f);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+static int mt312_get_tune_settings(struct dvb_frontend *fe,
+		struct dvb_frontend_tune_settings *fesettings)
 {
 	fesettings->min_delay_ms = 50;
 	fesettings->step_size = 0;
@@ -610,9 +655,9 @@ static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_
 	return 0;
 }
 
-static void mt312_release(struct dvb_frontend* fe)
+static void mt312_release(struct dvb_frontend *fe)
 {
-	struct mt312_state* state = fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -655,10 +700,10 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
 	.set_voltage = mt312_set_voltage,
 };
 
-struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
-					struct i2c_adapter* i2c)
+struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+					struct i2c_adapter *i2c)
 {
-	struct mt312_state* state = NULL;
+	struct mt312_state *state = NULL;
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
@@ -674,7 +719,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
 		goto error;
 
 	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+	memcpy(&state->frontend.ops, &vp310_mt312_ops,
+		sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
 	switch (state->id) {
@@ -687,7 +733,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
 		state->frequency = 60;
 		break;
 	default:
-		printk (KERN_WARNING "Only Zarlink VP310/MT312 are supported chips.\n");
+		printk(KERN_WARNING "Only Zarlink VP310/MT312"
+			" are supported chips.\n");
 		goto error;
 	}
 
@@ -697,6 +744,7 @@ error:
 	kfree(state);
 	return NULL;
 }
+EXPORT_SYMBOL(vp310_mt312_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
@@ -705,4 +753,3 @@ MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(vp310_mt312_attach);

+ 7 - 8
drivers/media/dvb/frontends/mt312.h

@@ -28,22 +28,21 @@
 
 #include <linux/dvb/frontend.h>
 
-struct mt312_config
-{
+struct mt312_config {
 	/* the demodulator's i2c address */
 	u8 demod_address;
 };
 
 #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
-struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
-					struct i2c_adapter* i2c);
+struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+					struct i2c_adapter *i2c);
 #else
-static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
-					struct i2c_adapter* i2c)
+static inline struct dvb_frontend *vp310_mt312_attach(
+	const struct mt312_config *config, struct i2c_adapter *i2c)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
 	return NULL;
 }
-#endif // CONFIG_DVB_MT312
+#endif /* CONFIG_DVB_MT312 */
 
-#endif // MT312_H
+#endif /* MT312_H */

+ 7 - 1
drivers/media/dvb/frontends/mt352.c

@@ -152,7 +152,13 @@ static void mt352_calc_input_freq(struct mt352_state* state,
 	if (state->config.if2)
 		if2 = state->config.if2;
 
-	ife = (2*adc_clock - if2);
+	if (adc_clock >= if2 * 2)
+		ife = if2;
+	else {
+		ife = adc_clock - (if2 % adc_clock);
+		if (ife > adc_clock / 2)
+			ife = adc_clock - ife;
+	}
 	value = -16374 * ife / adc_clock;
 	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
 		__FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff);

+ 1 - 5
drivers/media/dvb/frontends/or51132.c

@@ -564,7 +564,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
 	/* Allocate memory for the internal state */
 	state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL);
 	if (state == NULL)
-		goto error;
+		return NULL;
 
 	/* Setup the state */
 	state->config = config;
@@ -576,10 +576,6 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
 	memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
 }
 
 static struct dvb_frontend_ops or51132_ops = {

+ 1 - 5
drivers/media/dvb/frontends/or51211.c

@@ -529,7 +529,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
 	/* Allocate memory for the internal state */
 	state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL);
 	if (state == NULL)
-		goto error;
+		return NULL;
 
 	/* Setup the state */
 	state->config = config;
@@ -541,10 +541,6 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
 	memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
 }
 
 static struct dvb_frontend_ops or51211_ops = {

+ 76 - 21
drivers/media/dvb/frontends/s5h1409.c

@@ -42,6 +42,7 @@ struct s5h1409_state {
 	fe_modulation_t current_modulation;
 
 	u32 current_frequency;
+	int if_freq;
 
 	u32 is_qam_locked;
 	u32 qam_state;
@@ -97,7 +98,7 @@ static struct init_tab {
 	{ 0xac, 0x1003, },
 	{ 0xad, 0x103f, },
 	{ 0xe2, 0x0100, },
-	{ 0xe3, 0x0000, },
+	{ 0xe3, 0x1000, },
 	{ 0x28, 0x1010, },
 	{ 0xb1, 0x000e, },
 };
@@ -348,28 +349,32 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
 	return 0;
 }
 
+#define S5H1409_VSB_IF_FREQ 5380
+#define S5H1409_QAM_IF_FREQ state->config->qam_if
+
 static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
-	int ret = 0;
 
 	dprintk("%s(%d KHz)\n", __FUNCTION__, KHz);
 
-	if( (KHz == 44000) || (KHz == 5380) ) {
-		s5h1409_writereg(state, 0x87, 0x01be);
-		s5h1409_writereg(state, 0x88, 0x0436);
-		s5h1409_writereg(state, 0x89, 0x054d);
-	} else
-	if (KHz == 4000) {
+	switch (KHz) {
+	case 4000:
 		s5h1409_writereg(state, 0x87, 0x014b);
 		s5h1409_writereg(state, 0x88, 0x0cb5);
 		s5h1409_writereg(state, 0x89, 0x03e2);
-	} else {
-		printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
-		ret = -1;
+		break;
+	case 5380:
+	case 44000:
+	default:
+		s5h1409_writereg(state, 0x87, 0x01be);
+		s5h1409_writereg(state, 0x88, 0x0436);
+		s5h1409_writereg(state, 0x89, 0x054d);
+		break;
 	}
+	state->if_freq = KHz;
 
-	return ret;
+	return 0;
 }
 
 static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
@@ -394,11 +399,15 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
 	switch(m) {
 	case VSB_8:
 		dprintk("%s() VSB_8\n", __FUNCTION__);
+		if (state->if_freq != S5H1409_VSB_IF_FREQ)
+			s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
 		s5h1409_writereg(state, 0xf4, 0);
 		break;
 	case QAM_64:
 	case QAM_256:
 		dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__);
+		if (state->if_freq != S5H1409_QAM_IF_FREQ)
+			s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
 		s5h1409_writereg(state, 0xf4, 1);
 		s5h1409_writereg(state, 0x85, 0x110);
 		break;
@@ -432,9 +441,11 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
 	dprintk("%s(%d)\n", __FUNCTION__, enable);
 
 	if (enable)
-		return s5h1409_writereg(state, 0xe3, 0x1100);
+		return s5h1409_writereg(state, 0xe3,
+			s5h1409_readreg(state, 0xe3) | 0x1100);
 	else
-		return s5h1409_writereg(state, 0xe3, 0x1000);
+		return s5h1409_writereg(state, 0xe3,
+			s5h1409_readreg(state, 0xe3) & 0xeeff);
 }
 
 static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
@@ -504,13 +515,15 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
 			s5h1409_writereg(state, 0x96, 0x20);
 			s5h1409_writereg(state, 0xad,
 				( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
-			s5h1409_writereg(state, 0xab, 0x1100);
+			s5h1409_writereg(state, 0xab,
+				s5h1409_readreg(state, 0xab) & 0xeffe);
 		}
 	} else {
 		if (state->qam_state != 1) {
 			state->qam_state = 1;
 			s5h1409_writereg(state, 0x96, 0x08);
-			s5h1409_writereg(state, 0xab, 0x1101);
+			s5h1409_writereg(state, 0xab,
+				s5h1409_readreg(state, 0xab) | 0x1001);
 		}
 	}
 }
@@ -547,6 +560,36 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
 	return 0;
 }
 
+static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __FUNCTION__, mode);
+
+	val = s5h1409_readreg(state, 0xac) & 0xcfff;
+	switch (mode) {
+	case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
+		val |= 0x0000;
+		break;
+	case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
+		dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode);
+		val |= 0x1000;
+		break;
+	case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
+		val |= 0x2000;
+		break;
+	case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
+		val |= 0x3000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Configure MPEG Signal Timing charactistics */
+	return s5h1409_writereg(state, 0xac, val);
+}
+
 /* Reset the demod hardware and reset all of the configuration registers
    to a default state. */
 static int s5h1409_init (struct dvb_frontend* fe)
@@ -566,13 +609,16 @@ static int s5h1409_init (struct dvb_frontend* fe)
 	state->current_modulation = VSB_8;
 
 	if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
-		s5h1409_writereg(state, 0xab, 0x100); /* Serial */
+		s5h1409_writereg(state, 0xab,
+			s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
 	else
-		s5h1409_writereg(state, 0xab, 0x0); /* Parallel */
+		s5h1409_writereg(state, 0xab,
+			s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */
 
 	s5h1409_set_spectralinversion(fe, state->config->inversion);
-	s5h1409_set_if_freq(fe, state->config->if_freq);
+	s5h1409_set_if_freq(fe, state->if_freq);
 	s5h1409_set_gpio(fe, state->config->gpio);
+	s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing);
 	s5h1409_softreset(fe);
 
 	/* Note: Leaving the I2C gate closed. */
@@ -741,6 +787,7 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
 				    struct i2c_adapter* i2c)
 {
 	struct s5h1409_state* state = NULL;
+	u16 reg;
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
@@ -751,9 +798,11 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
 	state->config = config;
 	state->i2c = i2c;
 	state->current_modulation = 0;
+	state->if_freq = S5H1409_VSB_IF_FREQ;
 
 	/* check if the demod exists */
-	if (s5h1409_readreg(state, 0x04) != 0x0066)
+	reg = s5h1409_readreg(state, 0x04);
+	if ((reg != 0x0066) && (reg != 0x007f))
 		goto error;
 
 	/* create dvb_frontend */
@@ -761,8 +810,14 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
 	       sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
+	if (s5h1409_init(&state->frontend) != 0) {
+		printk(KERN_ERR "%s: Failed to initialize correctly\n",
+			__FUNCTION__);
+		goto error;
+	}
+
 	/* Note: Leaving the I2C gate open here. */
-	s5h1409_writereg(state, 0xf3, 1);
+	s5h1409_i2c_gate_ctrl(&state->frontend, 1);
 
 	return &state->frontend;
 

+ 9 - 2
drivers/media/dvb/frontends/s5h1409.h

@@ -39,8 +39,8 @@ struct s5h1409_config
 #define S5H1409_GPIO_ON  1
 	u8 gpio;
 
-	/* IF Freq in KHz */
-	u16 if_freq;
+	/* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */
+	u16 qam_if;
 
 	/* Spectral Inversion */
 #define S5H1409_INVERSION_OFF 0
@@ -51,6 +51,13 @@ struct s5h1409_config
 #define S5H1409_TUNERLOCKING 0
 #define S5H1409_DEMODLOCKING 1
 	u8 status_mode;
+
+	/* MPEG signal timing */
+#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
+#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
+#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
+#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+	u16 mpeg_timing;
 };
 
 #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))

+ 653 - 0
drivers/media/dvb/frontends/tda18271-common.c

@@ -0,0 +1,653 @@
+/*
+    tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "tda18271-priv.h"
+
+static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	enum tda18271_i2c_gate gate;
+	int ret = 0;
+
+	switch (priv->gate) {
+	case TDA18271_GATE_DIGITAL:
+	case TDA18271_GATE_ANALOG:
+		gate = priv->gate;
+		break;
+	case TDA18271_GATE_AUTO:
+	default:
+		switch (priv->mode) {
+		case TDA18271_DIGITAL:
+			gate = TDA18271_GATE_DIGITAL;
+			break;
+		case TDA18271_ANALOG:
+		default:
+			gate = TDA18271_GATE_ANALOG;
+			break;
+		}
+	}
+
+	switch (gate) {
+	case TDA18271_GATE_ANALOG:
+		if (fe->ops.analog_ops.i2c_gate_ctrl)
+			ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable);
+		break;
+	case TDA18271_GATE_DIGITAL:
+		if (fe->ops.i2c_gate_ctrl)
+			ret = fe->ops.i2c_gate_ctrl(fe, enable);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+};
+
+/*---------------------------------------------------------------------*/
+
+static void tda18271_dump_regs(struct dvb_frontend *fe, int extended)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda_reg("=== TDA18271 REG DUMP ===\n");
+	tda_reg("ID_BYTE            = 0x%02x\n", 0xff & regs[R_ID]);
+	tda_reg("THERMO_BYTE        = 0x%02x\n", 0xff & regs[R_TM]);
+	tda_reg("POWER_LEVEL_BYTE   = 0x%02x\n", 0xff & regs[R_PL]);
+	tda_reg("EASY_PROG_BYTE_1   = 0x%02x\n", 0xff & regs[R_EP1]);
+	tda_reg("EASY_PROG_BYTE_2   = 0x%02x\n", 0xff & regs[R_EP2]);
+	tda_reg("EASY_PROG_BYTE_3   = 0x%02x\n", 0xff & regs[R_EP3]);
+	tda_reg("EASY_PROG_BYTE_4   = 0x%02x\n", 0xff & regs[R_EP4]);
+	tda_reg("EASY_PROG_BYTE_5   = 0x%02x\n", 0xff & regs[R_EP5]);
+	tda_reg("CAL_POST_DIV_BYTE  = 0x%02x\n", 0xff & regs[R_CPD]);
+	tda_reg("CAL_DIV_BYTE_1     = 0x%02x\n", 0xff & regs[R_CD1]);
+	tda_reg("CAL_DIV_BYTE_2     = 0x%02x\n", 0xff & regs[R_CD2]);
+	tda_reg("CAL_DIV_BYTE_3     = 0x%02x\n", 0xff & regs[R_CD3]);
+	tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]);
+	tda_reg("MAIN_DIV_BYTE_1    = 0x%02x\n", 0xff & regs[R_MD1]);
+	tda_reg("MAIN_DIV_BYTE_2    = 0x%02x\n", 0xff & regs[R_MD2]);
+	tda_reg("MAIN_DIV_BYTE_3    = 0x%02x\n", 0xff & regs[R_MD3]);
+
+	/* only dump extended regs if DBG_ADV is set */
+	if (!(tda18271_debug & DBG_ADV))
+		return;
+
+	/* W indicates write-only registers.
+	 * Register dump for write-only registers shows last value written. */
+
+	tda_reg("EXTENDED_BYTE_1    = 0x%02x\n", 0xff & regs[R_EB1]);
+	tda_reg("EXTENDED_BYTE_2    = 0x%02x\n", 0xff & regs[R_EB2]);
+	tda_reg("EXTENDED_BYTE_3    = 0x%02x\n", 0xff & regs[R_EB3]);
+	tda_reg("EXTENDED_BYTE_4    = 0x%02x\n", 0xff & regs[R_EB4]);
+	tda_reg("EXTENDED_BYTE_5    = 0x%02x\n", 0xff & regs[R_EB5]);
+	tda_reg("EXTENDED_BYTE_6    = 0x%02x\n", 0xff & regs[R_EB6]);
+	tda_reg("EXTENDED_BYTE_7    = 0x%02x\n", 0xff & regs[R_EB7]);
+	tda_reg("EXTENDED_BYTE_8    = 0x%02x\n", 0xff & regs[R_EB8]);
+	tda_reg("EXTENDED_BYTE_9  W = 0x%02x\n", 0xff & regs[R_EB9]);
+	tda_reg("EXTENDED_BYTE_10   = 0x%02x\n", 0xff & regs[R_EB10]);
+	tda_reg("EXTENDED_BYTE_11   = 0x%02x\n", 0xff & regs[R_EB11]);
+	tda_reg("EXTENDED_BYTE_12   = 0x%02x\n", 0xff & regs[R_EB12]);
+	tda_reg("EXTENDED_BYTE_13   = 0x%02x\n", 0xff & regs[R_EB13]);
+	tda_reg("EXTENDED_BYTE_14   = 0x%02x\n", 0xff & regs[R_EB14]);
+	tda_reg("EXTENDED_BYTE_15   = 0x%02x\n", 0xff & regs[R_EB15]);
+	tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]);
+	tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]);
+	tda_reg("EXTENDED_BYTE_18   = 0x%02x\n", 0xff & regs[R_EB18]);
+	tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]);
+	tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]);
+	tda_reg("EXTENDED_BYTE_21   = 0x%02x\n", 0xff & regs[R_EB21]);
+	tda_reg("EXTENDED_BYTE_22   = 0x%02x\n", 0xff & regs[R_EB22]);
+	tda_reg("EXTENDED_BYTE_23   = 0x%02x\n", 0xff & regs[R_EB23]);
+}
+
+int tda18271_read_regs(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	unsigned char buf = 0x00;
+	int ret;
+	struct i2c_msg msg[] = {
+		{ .addr = priv->i2c_addr, .flags = 0,
+		  .buf = &buf, .len = 1 },
+		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
+		  .buf = regs, .len = 16 }
+	};
+
+	tda18271_i2c_gate_ctrl(fe, 1);
+
+	/* read all registers */
+	ret = i2c_transfer(priv->i2c_adap, msg, 2);
+
+	tda18271_i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+	if (tda18271_debug & DBG_REG)
+		tda18271_dump_regs(fe, 0);
+
+	return (ret == 2 ? 0 : ret);
+}
+
+int tda18271_read_extended(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	unsigned char regdump[TDA18271_NUM_REGS];
+	unsigned char buf = 0x00;
+	int ret, i;
+	struct i2c_msg msg[] = {
+		{ .addr = priv->i2c_addr, .flags = 0,
+		  .buf = &buf, .len = 1 },
+		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
+		  .buf = regdump, .len = TDA18271_NUM_REGS }
+	};
+
+	tda18271_i2c_gate_ctrl(fe, 1);
+
+	/* read all registers */
+	ret = i2c_transfer(priv->i2c_adap, msg, 2);
+
+	tda18271_i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+	for (i = 0; i <= TDA18271_NUM_REGS; i++) {
+		/* don't update write-only registers */
+		if ((i != R_EB9)  &&
+		    (i != R_EB16) &&
+		    (i != R_EB17) &&
+		    (i != R_EB19) &&
+		    (i != R_EB20))
+		regs[i] = regdump[i];
+	}
+
+	if (tda18271_debug & DBG_REG)
+		tda18271_dump_regs(fe, 1);
+
+	return (ret == 2 ? 0 : ret);
+}
+
+int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	unsigned char buf[TDA18271_NUM_REGS + 1];
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = len + 1 };
+	int i, ret;
+
+	BUG_ON((len == 0) || (idx + len > sizeof(buf)));
+
+	buf[0] = idx;
+	for (i = 1; i <= len; i++)
+		buf[i] = regs[idx - 1 + i];
+
+	tda18271_i2c_gate_ctrl(fe, 1);
+
+	/* write registers */
+	ret = i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tda18271_i2c_gate_ctrl(fe, 0);
+
+	if (ret != 1)
+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+	return (ret == 1 ? 0 : ret);
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_init_regs(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda_dbg("initializing registers for device @ %d-%04x\n",
+		i2c_adapter_id(priv->i2c_adap), priv->i2c_addr);
+
+	/* initialize registers */
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_ID]   = 0x83;
+		break;
+	case TDA18271HDC2:
+		regs[R_ID]   = 0x84;
+		break;
+	};
+
+	regs[R_TM]   = 0x08;
+	regs[R_PL]   = 0x80;
+	regs[R_EP1]  = 0xc6;
+	regs[R_EP2]  = 0xdf;
+	regs[R_EP3]  = 0x16;
+	regs[R_EP4]  = 0x60;
+	regs[R_EP5]  = 0x80;
+	regs[R_CPD]  = 0x80;
+	regs[R_CD1]  = 0x00;
+	regs[R_CD2]  = 0x00;
+	regs[R_CD3]  = 0x00;
+	regs[R_MPD]  = 0x00;
+	regs[R_MD1]  = 0x00;
+	regs[R_MD2]  = 0x00;
+	regs[R_MD3]  = 0x00;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB1]  = 0xff;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB1]  = 0xfc;
+		break;
+	};
+
+	regs[R_EB2]  = 0x01;
+	regs[R_EB3]  = 0x84;
+	regs[R_EB4]  = 0x41;
+	regs[R_EB5]  = 0x01;
+	regs[R_EB6]  = 0x84;
+	regs[R_EB7]  = 0x40;
+	regs[R_EB8]  = 0x07;
+	regs[R_EB9]  = 0x00;
+	regs[R_EB10] = 0x00;
+	regs[R_EB11] = 0x96;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB12] = 0x0f;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB12] = 0x33;
+		break;
+	};
+
+	regs[R_EB13] = 0xc1;
+	regs[R_EB14] = 0x00;
+	regs[R_EB15] = 0x8f;
+	regs[R_EB16] = 0x00;
+	regs[R_EB17] = 0x00;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB18] = 0x00;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB18] = 0x8c;
+		break;
+	};
+
+	regs[R_EB19] = 0x00;
+	regs[R_EB20] = 0x20;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB21] = 0x33;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB21] = 0xb3;
+		break;
+	};
+
+	regs[R_EB22] = 0x48;
+	regs[R_EB23] = 0xb0;
+
+	tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
+
+	/* setup agc1 gain */
+	regs[R_EB17] = 0x00;
+	tda18271_write_regs(fe, R_EB17, 1);
+	regs[R_EB17] = 0x03;
+	tda18271_write_regs(fe, R_EB17, 1);
+	regs[R_EB17] = 0x43;
+	tda18271_write_regs(fe, R_EB17, 1);
+	regs[R_EB17] = 0x4c;
+	tda18271_write_regs(fe, R_EB17, 1);
+
+	/* setup agc2 gain */
+	if ((priv->id) == TDA18271HDC1) {
+		regs[R_EB20] = 0xa0;
+		tda18271_write_regs(fe, R_EB20, 1);
+		regs[R_EB20] = 0xa7;
+		tda18271_write_regs(fe, R_EB20, 1);
+		regs[R_EB20] = 0xe7;
+		tda18271_write_regs(fe, R_EB20, 1);
+		regs[R_EB20] = 0xec;
+		tda18271_write_regs(fe, R_EB20, 1);
+	}
+
+	/* image rejection calibration */
+
+	/* low-band */
+	regs[R_EP3] = 0x1f;
+	regs[R_EP4] = 0x66;
+	regs[R_EP5] = 0x81;
+	regs[R_CPD] = 0xcc;
+	regs[R_CD1] = 0x6c;
+	regs[R_CD2] = 0x00;
+	regs[R_CD3] = 0x00;
+	regs[R_MPD] = 0xcd;
+	regs[R_MD1] = 0x77;
+	regs[R_MD2] = 0x08;
+	regs[R_MD3] = 0x00;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		tda18271_write_regs(fe, R_EP3, 11);
+		break;
+	case TDA18271HDC2:
+		tda18271_write_regs(fe, R_EP3, 12);
+		break;
+	};
+
+	if ((priv->id) == TDA18271HDC2) {
+		/* main pll cp source on */
+		regs[R_EB4] = 0x61;
+		tda18271_write_regs(fe, R_EB4, 1);
+		msleep(1);
+
+		/* main pll cp source off */
+		regs[R_EB4] = 0x41;
+		tda18271_write_regs(fe, R_EB4, 1);
+	}
+
+	msleep(5); /* pll locking */
+
+	/* launch detector */
+	tda18271_write_regs(fe, R_EP1, 1);
+	msleep(5); /* wanted low measurement */
+
+	regs[R_EP5] = 0x85;
+	regs[R_CPD] = 0xcb;
+	regs[R_CD1] = 0x66;
+	regs[R_CD2] = 0x70;
+
+	tda18271_write_regs(fe, R_EP3, 7);
+	msleep(5); /* pll locking */
+
+	/* launch optimization algorithm */
+	tda18271_write_regs(fe, R_EP2, 1);
+	msleep(30); /* image low optimization completion */
+
+	/* mid-band */
+	regs[R_EP5] = 0x82;
+	regs[R_CPD] = 0xa8;
+	regs[R_CD2] = 0x00;
+	regs[R_MPD] = 0xa9;
+	regs[R_MD1] = 0x73;
+	regs[R_MD2] = 0x1a;
+
+	tda18271_write_regs(fe, R_EP3, 11);
+	msleep(5); /* pll locking */
+
+	tda18271_write_regs(fe, R_EP1, 1);
+	msleep(5); /* wanted mid measurement */
+
+	regs[R_EP5] = 0x86;
+	regs[R_CPD] = 0xa8;
+	regs[R_CD1] = 0x66;
+	regs[R_CD2] = 0xa0;
+
+	tda18271_write_regs(fe, R_EP3, 7);
+	msleep(5); /* pll locking */
+
+	/* launch optimization algorithm */
+	tda18271_write_regs(fe, R_EP2, 1);
+	msleep(30); /* image mid optimization completion */
+
+	/* high-band */
+	regs[R_EP5] = 0x83;
+	regs[R_CPD] = 0x98;
+	regs[R_CD1] = 0x65;
+	regs[R_CD2] = 0x00;
+	regs[R_MPD] = 0x99;
+	regs[R_MD1] = 0x71;
+	regs[R_MD2] = 0xcd;
+
+	tda18271_write_regs(fe, R_EP3, 11);
+	msleep(5); /* pll locking */
+
+	/* launch detector */
+	tda18271_write_regs(fe, R_EP1, 1);
+	msleep(5); /* wanted high measurement */
+
+	regs[R_EP5] = 0x87;
+	regs[R_CD1] = 0x65;
+	regs[R_CD2] = 0x50;
+
+	tda18271_write_regs(fe, R_EP3, 7);
+	msleep(5); /* pll locking */
+
+	/* launch optimization algorithm */
+	tda18271_write_regs(fe, R_EP2, 1);
+	msleep(30); /* image high optimization completion */
+
+	/* return to normal mode */
+	regs[R_EP4] = 0x64;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	/* synchronize */
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+/*
+ *  Standby modes, EP3 [7:5]
+ *
+ *  | SM  || SM_LT || SM_XT || mode description
+ *  |=====\\=======\\=======\\===================================
+ *  |  0  ||   0   ||   0   || normal mode
+ *  |-----||-------||-------||-----------------------------------
+ *  |     ||       ||       || standby mode w/ slave tuner output
+ *  |  1  ||   0   ||   0   || & loop thru & xtal oscillator on
+ *  |-----||-------||-------||-----------------------------------
+ *  |  1  ||   1   ||   0   || standby mode w/ xtal oscillator on
+ *  |-----||-------||-------||-----------------------------------
+ *  |  1  ||   1   ||   1   || power off
+ *
+ */
+
+int tda18271_set_standby_mode(struct dvb_frontend *fe,
+			      int sm, int sm_lt, int sm_xt)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
+
+	regs[R_EP3]  &= ~0xe0; /* clear sm, sm_lt, sm_xt */
+	regs[R_EP3]  |= sm    ? (1 << 7) : 0 |
+			sm_lt ? (1 << 6) : 0 |
+			sm_xt ? (1 << 5) : 0;
+
+	tda18271_write_regs(fe, R_EP3, 1);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq)
+{
+	/* sets main post divider & divider bytes, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 d, pd;
+	u32 div;
+
+	int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_MPD]   = (0x77 & pd);
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_MPD]  &= ~0x08;
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_MPD]  |=  0x08;
+		break;
+	}
+
+	div =  ((d * (freq / 1000)) << 7) / 125;
+
+	regs[R_MD1]   = 0x7f & (div >> 16);
+	regs[R_MD2]   = 0xff & (div >> 8);
+	regs[R_MD3]   = 0xff & div;
+fail:
+	return ret;
+}
+
+int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq)
+{
+	/* sets cal post divider & divider bytes, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 d, pd;
+	u32 div;
+
+	int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_CPD]   = pd;
+
+	div =  ((d * (freq / 1000)) << 7) / 125;
+
+	regs[R_CD1]   = 0x7f & (div >> 16);
+	regs[R_CD2]   = 0xff & (div >> 8);
+	regs[R_CD3]   = 0xff & div;
+fail:
+	return ret;
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets bp filter bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EP1]  &= ~0x07; /* clear bp filter bits */
+	regs[R_EP1]  |= (0x07 & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets K & M bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EB13] &= ~0x7c; /* clear k & m bits */
+	regs[R_EB13] |= (0x7c & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets rf band bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EP2]  &= ~0xe0; /* clear rf band bits */
+	regs[R_EP2]  |= (0xe0 & (val << 5));
+fail:
+	return ret;
+}
+
+int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets gain taper bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EP2]  &= ~0x1f; /* clear gain taper bits */
+	regs[R_EP2]  |= (0x1f & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets IR Meas bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EP5] &= ~0x07;
+	regs[R_EP5] |= (0x07 & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets rf cal byte (RFC_Cprog), but does not write it */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	tda18271_lookup_map(fe, RF_CAL, freq, &val);
+
+	regs[R_EB14] = val;
+
+	return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */

+ 1225 - 0
drivers/media/dvb/frontends/tda18271-fe.c

@@ -0,0 +1,1225 @@
+/*
+    tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include "tda18271-priv.h"
+
+int tda18271_debug;
+module_param_named(debug, tda18271_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level "
+		 "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
+
+static int tda18271_cal_on_startup;
+module_param_named(cal, tda18271_cal_on_startup, int, 0644);
+MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
+
+static LIST_HEAD(tda18271_list);
+static DEFINE_MUTEX(tda18271_list_mutex);
+
+/*---------------------------------------------------------------------*/
+
+static int tda18271_ir_cal_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda18271_read_regs(fe);
+
+	/* test IR_CAL_OK to see if we need init */
+	if ((regs[R_EP1] & 0x08) == 0)
+		tda18271_init_regs(fe);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_channel_configuration(struct dvb_frontend *fe,
+					  u32 ifc, u32 freq, u32 bw, u8 std,
+					  int radio)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u32 N;
+
+	/* update TV broadcast parameters */
+
+	/* set standard */
+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
+	regs[R_EP3]  |= std;
+
+	/* set cal mode to normal */
+	regs[R_EP4]  &= ~0x03;
+
+	/* update IF output level & IF notch frequency */
+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_EP4]  |= 0x04; /* IF level = 1 */
+		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
+		break;
+	}
+
+	if (radio)
+		regs[R_EP4]  |=  0x80;
+	else
+		regs[R_EP4]  &= ~0x80;
+
+	/* update RF_TOP / IF_TOP */
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_EB22]  = 0x2c;
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_EB22]  = 0x37;
+		break;
+	}
+	tda18271_write_regs(fe, R_EB22, 1);
+
+	/* --------------------------------------------------------------- */
+
+	/* disable Power Level Indicator */
+	regs[R_EP1]  |= 0x40;
+
+	/* frequency dependent parameters */
+
+	tda18271_calc_ir_measure(fe, &freq);
+
+	tda18271_calc_bp_filter(fe, &freq);
+
+	tda18271_calc_rf_band(fe, &freq);
+
+	tda18271_calc_gain_taper(fe, &freq);
+
+	/* --------------------------------------------------------------- */
+
+	/* dual tuner and agc1 extra configuration */
+
+	/* main vco when Master, cal vco when slave */
+	regs[R_EB1]  |= 0x04; /* FIXME: assumes master */
+
+	/* agc1 always active */
+	regs[R_EB1]  &= ~0x02;
+
+	/* agc1 has priority on agc2 */
+	regs[R_EB1]  &= ~0x01;
+
+	tda18271_write_regs(fe, R_EB1, 1);
+
+	/* --------------------------------------------------------------- */
+
+	N = freq + ifc;
+
+	/* FIXME: assumes master */
+	tda18271_calc_main_pll(fe, N);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	tda18271_write_regs(fe, R_TM, 7);
+
+	/* main pll charge pump source */
+	regs[R_EB4] |= 0x20;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	msleep(1);
+
+	/* normal operation for the main pll */
+	regs[R_EB4] &= ~0x20;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	msleep(5);
+
+	return 0;
+}
+
+static int tda18271_read_thermometer(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int tm;
+
+	/* switch thermometer on */
+	regs[R_TM]   |= 0x10;
+	tda18271_write_regs(fe, R_TM, 1);
+
+	/* read thermometer info */
+	tda18271_read_regs(fe);
+
+	if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) ||
+	    (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) {
+
+		if ((regs[R_TM] & 0x20) == 0x20)
+			regs[R_TM] &= ~0x20;
+		else
+			regs[R_TM] |= 0x20;
+
+		tda18271_write_regs(fe, R_TM, 1);
+
+		msleep(10); /* temperature sensing */
+
+		/* read thermometer info */
+		tda18271_read_regs(fe);
+	}
+
+	tm = tda18271_lookup_thermometer(fe);
+
+	/* switch thermometer off */
+	regs[R_TM]   &= ~0x10;
+	tda18271_write_regs(fe, R_TM, 1);
+
+	/* set CAL mode to normal */
+	regs[R_EP4]  &= ~0x03;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	return tm;
+}
+
+static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe,
+						   u32 freq)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+	unsigned char *regs = priv->tda18271_regs;
+	int tm_current, rfcal_comp, approx, i;
+	u8 dc_over_dt, rf_tab;
+
+	/* power up */
+	tda18271_set_standby_mode(fe, 0, 0, 0);
+
+	/* read die current temperature */
+	tm_current = tda18271_read_thermometer(fe);
+
+	/* frequency dependent parameters */
+
+	tda18271_calc_rf_cal(fe, &freq);
+	rf_tab = regs[R_EB14];
+
+	i = tda18271_lookup_rf_band(fe, &freq, NULL);
+	if (i < 0)
+		return -EINVAL;
+
+	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
+		approx = map[i].rf_a1 *
+			(freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab;
+	} else {
+		approx = map[i].rf_a2 *
+			(freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab;
+	}
+
+	if (approx < 0)
+		approx = 0;
+	if (approx > 255)
+		approx = 255;
+
+	tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
+
+	/* calculate temperature compensation */
+	rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal);
+
+	regs[R_EB14] = approx + rfcal_comp;
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	return 0;
+}
+
+static int tda18271_por(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	/* power up detector 1 */
+	regs[R_EB12] &= ~0x20;
+	tda18271_write_regs(fe, R_EB12, 1);
+
+	regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
+	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
+
+	/* POR mode */
+	tda18271_set_standby_mode(fe, 1, 0, 0);
+
+	/* disable 1.5 MHz low pass filter */
+	regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
+	regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
+	tda18271_write_regs(fe, R_EB21, 3);
+
+	return 0;
+}
+
+static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u32 N;
+
+	/* set CAL mode to normal */
+	regs[R_EP4]  &= ~0x03;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	/* switch off agc1 */
+	regs[R_EP3]  |= 0x40; /* sm_lt = 1 */
+
+	regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	/* frequency dependent parameters */
+
+	tda18271_calc_bp_filter(fe, &freq);
+	tda18271_calc_gain_taper(fe, &freq);
+	tda18271_calc_rf_band(fe, &freq);
+	tda18271_calc_km(fe, &freq);
+
+	tda18271_write_regs(fe, R_EP1, 3);
+	tda18271_write_regs(fe, R_EB13, 1);
+
+	/* main pll charge pump source */
+	regs[R_EB4]  |= 0x20;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	/* cal pll charge pump source */
+	regs[R_EB7]  |= 0x20;
+	tda18271_write_regs(fe, R_EB7, 1);
+
+	/* force dcdc converter to 0 V */
+	regs[R_EB14] = 0x00;
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	/* disable plls lock */
+	regs[R_EB20] &= ~0x20;
+	tda18271_write_regs(fe, R_EB20, 1);
+
+	/* set CAL mode to RF tracking filter calibration */
+	regs[R_EP4]  |= 0x03;
+	tda18271_write_regs(fe, R_EP4, 2);
+
+	/* --------------------------------------------------------------- */
+
+	/* set the internal calibration signal */
+	N = freq;
+
+	tda18271_calc_main_pll(fe, N);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	/* downconvert internal calibration */
+	N += 1000000;
+
+	tda18271_calc_main_pll(fe, N);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	msleep(5);
+
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	/* --------------------------------------------------------------- */
+
+	/* normal operation for the main pll */
+	regs[R_EB4] &= ~0x20;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	/* normal operation for the cal pll  */
+	regs[R_EB7] &= ~0x20;
+	tda18271_write_regs(fe, R_EB7, 1);
+
+	msleep(5); /* plls locking */
+
+	/* launch the rf tracking filters calibration */
+	regs[R_EB20]  |= 0x20;
+	tda18271_write_regs(fe, R_EB20, 1);
+
+	msleep(60); /* calibration */
+
+	/* --------------------------------------------------------------- */
+
+	/* set CAL mode to normal */
+	regs[R_EP4]  &= ~0x03;
+
+	/* switch on agc1 */
+	regs[R_EP3]  &= ~0x40; /* sm_lt = 0 */
+
+	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	tda18271_write_regs(fe, R_EP3, 2);
+
+	/* synchronization */
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	/* get calibration result */
+	tda18271_read_extended(fe);
+
+	return regs[R_EB14];
+}
+
+static int tda18271_powerscan(struct dvb_frontend *fe,
+			      u32 *freq_in, u32 *freq_out)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int sgn, bcal, count, wait;
+	u8 cid_target;
+	u16 count_limit;
+	u32 freq;
+
+	freq = *freq_in;
+
+	tda18271_calc_rf_band(fe, &freq);
+	tda18271_calc_rf_cal(fe, &freq);
+	tda18271_calc_gain_taper(fe, &freq);
+	tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit);
+
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	/* downconvert frequency */
+	freq += 1000000;
+
+	tda18271_calc_main_pll(fe, freq);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	msleep(5); /* pll locking */
+
+	/* detection mode */
+	regs[R_EP4]  &= ~0x03;
+	regs[R_EP4]  |= 0x01;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	/* launch power detection measurement */
+	tda18271_write_regs(fe, R_EP2, 1);
+
+	/* read power detection info, stored in EB10 */
+	tda18271_read_extended(fe);
+
+	/* algorithm initialization */
+	sgn = 1;
+	*freq_out = *freq_in;
+	bcal = 0;
+	count = 0;
+	wait = false;
+
+	while ((regs[R_EB10] & 0x3f) < cid_target) {
+		/* downconvert updated freq to 1 MHz */
+		freq = *freq_in + (sgn * count) + 1000000;
+
+		tda18271_calc_main_pll(fe, freq);
+		tda18271_write_regs(fe, R_MPD, 4);
+
+		if (wait) {
+			msleep(5); /* pll locking */
+			wait = false;
+		} else
+			udelay(100); /* pll locking */
+
+		/* launch power detection measurement */
+		tda18271_write_regs(fe, R_EP2, 1);
+
+		/* read power detection info, stored in EB10 */
+		tda18271_read_extended(fe);
+
+		count += 200;
+
+		if (count < count_limit)
+			continue;
+
+		if (sgn <= 0)
+			break;
+
+		sgn = -1 * sgn;
+		count = 200;
+		wait = true;
+	}
+
+	if ((regs[R_EB10] & 0x3f) >= cid_target) {
+		bcal = 1;
+		*freq_out = freq - 1000000;
+	} else
+		bcal = 0;
+
+	tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
+		bcal, *freq_in, *freq_out, freq);
+
+	return bcal;
+}
+
+static int tda18271_powerscan_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	/* set standard to digital */
+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
+	regs[R_EP3]  |= 0x12;
+
+	/* set cal mode to normal */
+	regs[R_EP4]  &= ~0x03;
+
+	/* update IF output level & IF notch frequency */
+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+
+	tda18271_write_regs(fe, R_EP3, 2);
+
+	regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
+
+	/* 1.5 MHz low pass filter */
+	regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
+	regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
+
+	tda18271_write_regs(fe, R_EB21, 3);
+
+	return 0;
+}
+
+static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+	unsigned char *regs = priv->tda18271_regs;
+	int bcal, rf, i;
+#define RF1 0
+#define RF2 1
+#define RF3 2
+	u32 rf_default[3];
+	u32 rf_freq[3];
+	u8 prog_cal[3];
+	u8 prog_tab[3];
+
+	i = tda18271_lookup_rf_band(fe, &freq, NULL);
+
+	if (i < 0)
+		return i;
+
+	rf_default[RF1] = 1000 * map[i].rf1_def;
+	rf_default[RF2] = 1000 * map[i].rf2_def;
+	rf_default[RF3] = 1000 * map[i].rf3_def;
+
+	for (rf = RF1; rf <= RF3; rf++) {
+		if (0 == rf_default[rf])
+			return 0;
+		tda_cal("freq = %d, rf = %d\n", freq, rf);
+
+		/* look for optimized calibration frequency */
+		bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
+
+		tda18271_calc_rf_cal(fe, &rf_freq[rf]);
+		prog_tab[rf] = regs[R_EB14];
+
+		if (1 == bcal)
+			prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]);
+		else
+			prog_cal[rf] = prog_tab[rf];
+
+		switch (rf) {
+		case RF1:
+			map[i].rf_a1 = 0;
+			map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1];
+			map[i].rf1   = rf_freq[RF1] / 1000;
+			break;
+		case RF2:
+			map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] -
+					prog_cal[RF1] + prog_tab[RF1]) /
+				((rf_freq[RF2] - rf_freq[RF1]) / 1000);
+			map[i].rf2   = rf_freq[RF2] / 1000;
+			break;
+		case RF3:
+			map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] -
+					prog_cal[RF2] + prog_tab[RF2]) /
+				((rf_freq[RF3] - rf_freq[RF2]) / 1000);
+			map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2];
+			map[i].rf3   = rf_freq[RF3] / 1000;
+			break;
+		default:
+			BUG();
+		}
+	}
+
+	return 0;
+}
+
+static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned int i;
+
+	tda_info("tda18271: performing RF tracking filter calibration\n");
+
+	/* wait for die temperature stabilization */
+	msleep(200);
+
+	tda18271_powerscan_init(fe);
+
+	/* rf band calibration */
+	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++)
+		tda18271_rf_tracking_filters_init(fe, 1000 *
+						  priv->rf_cal_state[i].rfmax);
+
+	priv->tm_rfcal = tda18271_read_thermometer(fe);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_rf_cal_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	/* test RF_CAL_OK to see if we need init */
+	if ((regs[R_EP1] & 0x10) == 0)
+		priv->cal_initialized = false;
+
+	if (priv->cal_initialized)
+		return 0;
+
+	tda18271_calc_rf_filter_curve(fe);
+
+	tda18271_por(fe);
+
+	tda_info("tda18271: RF tracking filter calibration complete\n");
+
+	priv->cal_initialized = true;
+
+	return 0;
+}
+
+static int tda18271_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&priv->lock);
+
+	/* power up */
+	tda18271_set_standby_mode(fe, 0, 0, 0);
+
+	/* initialization */
+	tda18271_ir_cal_init(fe);
+
+	if (priv->id == TDA18271HDC2)
+		tda18271_rf_cal_init(fe);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int tda18271c2_tune(struct dvb_frontend *fe,
+			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
+
+	tda18271_init(fe);
+
+	mutex_lock(&priv->lock);
+
+	tda18271_rf_tracking_filters_correction(fe, freq);
+
+	tda18271_channel_configuration(fe, ifc, freq, bw, std, radio);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271c1_tune(struct dvb_frontend *fe,
+			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u32 N = 0;
+
+	tda18271_init(fe);
+
+	mutex_lock(&priv->lock);
+
+	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
+
+	/* RF tracking filter calibration */
+
+	/* calculate bp filter */
+	tda18271_calc_bp_filter(fe, &freq);
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	regs[R_EB4]  &= 0x07;
+	regs[R_EB4]  |= 0x60;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	regs[R_EB7]   = 0x60;
+	tda18271_write_regs(fe, R_EB7, 1);
+
+	regs[R_EB14]  = 0x00;
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	regs[R_EB20]  = 0xcc;
+	tda18271_write_regs(fe, R_EB20, 1);
+
+	/* set cal mode to RF tracking filter calibration */
+	regs[R_EP4]  |= 0x03;
+
+	/* calculate cal pll */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		N = freq - 1250000;
+		break;
+	case TDA18271_DIGITAL:
+		N = freq + bw / 2;
+		break;
+	}
+
+	tda18271_calc_cal_pll(fe, N);
+
+	/* calculate main pll */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		N = freq - 250000;
+		break;
+	case TDA18271_DIGITAL:
+		N = freq + bw / 2 + 1000000;
+		break;
+	}
+
+	tda18271_calc_main_pll(fe, N);
+
+	tda18271_write_regs(fe, R_EP3, 11);
+	msleep(5); /* RF tracking filter calibration initialization */
+
+	/* search for K,M,CO for RF calibration */
+	tda18271_calc_km(fe, &freq);
+	tda18271_write_regs(fe, R_EB13, 1);
+
+	/* search for rf band */
+	tda18271_calc_rf_band(fe, &freq);
+
+	/* search for gain taper */
+	tda18271_calc_gain_taper(fe, &freq);
+
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	regs[R_EB4]  &= 0x07;
+	regs[R_EB4]  |= 0x40;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	regs[R_EB7]   = 0x40;
+	tda18271_write_regs(fe, R_EB7, 1);
+	msleep(10);
+
+	regs[R_EB20]  = 0xec;
+	tda18271_write_regs(fe, R_EB20, 1);
+	msleep(60); /* RF tracking filter calibration completion */
+
+	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	/* RF tracking filter correction for VHF_Low band */
+	if (0 == tda18271_calc_rf_cal(fe, &freq))
+		tda18271_write_regs(fe, R_EB14, 1);
+
+	/* Channel Configuration */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_EB22]  = 0x2c;
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_EB22]  = 0x37;
+		break;
+	}
+	tda18271_write_regs(fe, R_EB22, 1);
+
+	regs[R_EP1]  |= 0x40; /* set dis power level on */
+
+	/* set standard */
+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
+
+	/* see table 22 */
+	regs[R_EP3]  |= std;
+
+	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
+
+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_EP4]  |= 0x04;
+		regs[R_MPD]  |= 0x80;
+		break;
+	}
+
+	if (radio)
+		regs[R_EP4]  |=  0x80;
+	else
+		regs[R_EP4]  &= ~0x80;
+
+	/* image rejection validity */
+	tda18271_calc_ir_measure(fe, &freq);
+
+	/* calculate MAIN PLL */
+	N = freq + ifc;
+
+	tda18271_calc_main_pll(fe, N);
+
+	tda18271_write_regs(fe, R_TM, 15);
+	msleep(5);
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static inline int tda18271_tune(struct dvb_frontend *fe,
+				u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio);
+		break;
+	case TDA18271HDC2:
+		ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio);
+		break;
+	}
+	return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_set_params(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *params)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std_map = &priv->std;
+	int ret;
+	u8 std;
+	u16 sgIF;
+	u32 bw, freq = params->frequency;
+
+	priv->mode = TDA18271_DIGITAL;
+
+	if (fe->ops.info.type == FE_ATSC) {
+		switch (params->u.vsb.modulation) {
+		case VSB_8:
+		case VSB_16:
+			std  = std_map->atsc_6.std_bits;
+			sgIF = std_map->atsc_6.if_freq;
+			break;
+		case QAM_64:
+		case QAM_256:
+			std  = std_map->qam_6.std_bits;
+			sgIF = std_map->qam_6.if_freq;
+			break;
+		default:
+			tda_warn("modulation not set!\n");
+			return -EINVAL;
+		}
+#if 0
+		/* userspace request is already center adjusted */
+		freq += 1750000; /* Adjust to center (+1.75MHZ) */
+#endif
+		bw = 6000000;
+	} else if (fe->ops.info.type == FE_OFDM) {
+		switch (params->u.ofdm.bandwidth) {
+		case BANDWIDTH_6_MHZ:
+			bw = 6000000;
+			std  = std_map->dvbt_6.std_bits;
+			sgIF = std_map->dvbt_6.if_freq;
+			break;
+		case BANDWIDTH_7_MHZ:
+			bw = 7000000;
+			std  = std_map->dvbt_7.std_bits;
+			sgIF = std_map->dvbt_7.if_freq;
+			break;
+		case BANDWIDTH_8_MHZ:
+			bw = 8000000;
+			std  = std_map->dvbt_8.std_bits;
+			sgIF = std_map->dvbt_8.if_freq;
+			break;
+		default:
+			tda_warn("bandwidth not set!\n");
+			return -EINVAL;
+		}
+	} else {
+		tda_warn("modulation type not supported!\n");
+		return -EINVAL;
+	}
+
+	/* When tuning digital, the analog demod must be tri-stated */
+	if (fe->ops.analog_ops.standby)
+		fe->ops.analog_ops.standby(fe);
+
+	ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0);
+
+	if (ret < 0)
+		goto fail;
+
+	priv->frequency = freq;
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
+		params->u.ofdm.bandwidth : 0;
+fail:
+	return ret;
+}
+
+static int tda18271_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std_map = &priv->std;
+	char *mode;
+	int ret, radio = 0;
+	u8 std;
+	u16 sgIF;
+	u32 freq = params->frequency * 62500;
+
+	priv->mode = TDA18271_ANALOG;
+
+	if (params->mode == V4L2_TUNER_RADIO) {
+		radio = 1;
+		freq = freq / 1000;
+		std  = std_map->fm_radio.std_bits;
+		sgIF = std_map->fm_radio.if_freq;
+		mode = "fm";
+	} else if (params->std & V4L2_STD_MN) {
+		std  = std_map->atv_mn.std_bits;
+		sgIF = std_map->atv_mn.if_freq;
+		mode = "MN";
+	} else if (params->std & V4L2_STD_B) {
+		std  = std_map->atv_b.std_bits;
+		sgIF = std_map->atv_b.if_freq;
+		mode = "B";
+	} else if (params->std & V4L2_STD_GH) {
+		std  = std_map->atv_gh.std_bits;
+		sgIF = std_map->atv_gh.if_freq;
+		mode = "GH";
+	} else if (params->std & V4L2_STD_PAL_I) {
+		std  = std_map->atv_i.std_bits;
+		sgIF = std_map->atv_i.if_freq;
+		mode = "I";
+	} else if (params->std & V4L2_STD_DK) {
+		std  = std_map->atv_dk.std_bits;
+		sgIF = std_map->atv_dk.if_freq;
+		mode = "DK";
+	} else if (params->std & V4L2_STD_SECAM_L) {
+		std  = std_map->atv_l.std_bits;
+		sgIF = std_map->atv_l.if_freq;
+		mode = "L";
+	} else if (params->std & V4L2_STD_SECAM_LC) {
+		std  = std_map->atv_lc.std_bits;
+		sgIF = std_map->atv_lc.if_freq;
+		mode = "L'";
+	} else {
+		std  = std_map->atv_i.std_bits;
+		sgIF = std_map->atv_i.if_freq;
+		mode = "xx";
+	}
+
+	tda_dbg("setting tda18271 to system %s\n", mode);
+
+	ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio);
+
+	if (ret < 0)
+		goto fail;
+
+	priv->frequency = freq;
+	priv->bandwidth = 0;
+fail:
+	return ret;
+}
+
+static int tda18271_sleep(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&priv->lock);
+
+	/* standby mode w/ slave tuner output
+	 * & loop thru & xtal oscillator on */
+	tda18271_set_standby_mode(fe, 1, 0, 0);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int tda18271_release(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&tda18271_list_mutex);
+
+	priv->count--;
+
+	if (!priv->count) {
+		tda_dbg("destroying instance @ %d-%04x\n",
+			i2c_adapter_id(priv->i2c_adap),
+			priv->i2c_addr);
+		list_del(&priv->tda18271_list);
+
+		kfree(priv);
+	}
+	mutex_unlock(&tda18271_list_mutex);
+
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+#define tda18271_update_std(std_cfg, name) do {				\
+	if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) {		\
+		tda_dbg("Using custom std config for %s\n", name);	\
+		memcpy(&std->std_cfg, &map->std_cfg,			\
+			sizeof(struct tda18271_std_map_item));		\
+	} } while (0)
+
+#define tda18271_dump_std_item(std_cfg, name) do {			\
+	tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n",		\
+		name, std->std_cfg.if_freq, std->std_cfg.std_bits);	\
+	} while (0)
+
+static int tda18271_dump_std_map(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std = &priv->std;
+
+	tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
+	tda18271_dump_std_item(fm_radio, "fm");
+	tda18271_dump_std_item(atv_b,  "pal b");
+	tda18271_dump_std_item(atv_dk, "pal dk");
+	tda18271_dump_std_item(atv_gh, "pal gh");
+	tda18271_dump_std_item(atv_i,  "pal i");
+	tda18271_dump_std_item(atv_l,  "pal l");
+	tda18271_dump_std_item(atv_lc, "pal l'");
+	tda18271_dump_std_item(atv_mn, "atv mn");
+	tda18271_dump_std_item(atsc_6, "atsc 6");
+	tda18271_dump_std_item(dvbt_6, "dvbt 6");
+	tda18271_dump_std_item(dvbt_7, "dvbt 7");
+	tda18271_dump_std_item(dvbt_8, "dvbt 8");
+	tda18271_dump_std_item(qam_6,  "qam 6");
+	tda18271_dump_std_item(qam_8,  "qam 8");
+
+	return 0;
+}
+
+static int tda18271_update_std_map(struct dvb_frontend *fe,
+				   struct tda18271_std_map *map)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std = &priv->std;
+
+	if (!map)
+		return -EINVAL;
+
+	tda18271_update_std(fm_radio, "fm");
+	tda18271_update_std(atv_b,  "atv b");
+	tda18271_update_std(atv_dk, "atv dk");
+	tda18271_update_std(atv_gh, "atv gh");
+	tda18271_update_std(atv_i,  "atv i");
+	tda18271_update_std(atv_l,  "atv l");
+	tda18271_update_std(atv_lc, "atv l'");
+	tda18271_update_std(atv_mn, "atv mn");
+	tda18271_update_std(atsc_6, "atsc 6");
+	tda18271_update_std(dvbt_6, "dvbt 6");
+	tda18271_update_std(dvbt_7, "dvbt 7");
+	tda18271_update_std(dvbt_8, "dvbt 8");
+	tda18271_update_std(qam_6,  "qam 6");
+	tda18271_update_std(qam_8,  "qam 8");
+
+	return 0;
+}
+
+static int tda18271_get_id(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	char *name;
+	int ret = 0;
+
+	mutex_lock(&priv->lock);
+	tda18271_read_regs(fe);
+	mutex_unlock(&priv->lock);
+
+	switch (regs[R_ID] & 0x7f) {
+	case 3:
+		name = "TDA18271HD/C1";
+		priv->id = TDA18271HDC1;
+		break;
+	case 4:
+		name = "TDA18271HD/C2";
+		priv->id = TDA18271HDC2;
+		break;
+	default:
+		name = "Unknown device";
+		ret = -EINVAL;
+		break;
+	}
+
+	tda_info("%s detected @ %d-%04x%s\n", name,
+		 i2c_adapter_id(priv->i2c_adap), priv->i2c_addr,
+		 (0 == ret) ? "" : ", device not supported.");
+
+	return ret;
+}
+
+static struct dvb_tuner_ops tda18271_tuner_ops = {
+	.info = {
+		.name = "NXP TDA18271HD",
+		.frequency_min  =  45000000,
+		.frequency_max  = 864000000,
+		.frequency_step =     62500
+	},
+	.init              = tda18271_init,
+	.sleep             = tda18271_sleep,
+	.set_params        = tda18271_set_params,
+	.set_analog_params = tda18271_set_analog_params,
+	.release           = tda18271_release,
+	.get_frequency     = tda18271_get_frequency,
+	.get_bandwidth     = tda18271_get_bandwidth,
+};
+
+struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
+				     struct i2c_adapter *i2c,
+				     struct tda18271_config *cfg)
+{
+	struct tda18271_priv *priv = NULL;
+	int state_found = 0;
+
+	mutex_lock(&tda18271_list_mutex);
+
+	list_for_each_entry(priv, &tda18271_list, tda18271_list) {
+		if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) &&
+		    (priv->i2c_addr == addr)) {
+			tda_dbg("attaching existing tuner @ %d-%04x\n",
+				i2c_adapter_id(priv->i2c_adap),
+				priv->i2c_addr);
+			priv->count++;
+			fe->tuner_priv = priv;
+			state_found = 1;
+			/* allow dvb driver to override i2c gate setting */
+			if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
+				priv->gate = cfg->gate;
+			break;
+		}
+	}
+	if (state_found == 0) {
+		tda_dbg("creating new tuner instance @ %d-%04x\n",
+			i2c_adapter_id(i2c), addr);
+
+		priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
+		if (priv == NULL) {
+			mutex_unlock(&tda18271_list_mutex);
+			return NULL;
+		}
+
+		priv->i2c_addr = addr;
+		priv->i2c_adap = i2c;
+		priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+		priv->cal_initialized = false;
+		mutex_init(&priv->lock);
+		priv->count++;
+
+		fe->tuner_priv = priv;
+
+		list_add_tail(&priv->tda18271_list, &tda18271_list);
+
+		if (tda18271_get_id(fe) < 0)
+			goto fail;
+
+		if (tda18271_assign_map_layout(fe) < 0)
+			goto fail;
+
+		mutex_lock(&priv->lock);
+		tda18271_init_regs(fe);
+
+		if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2))
+			tda18271_rf_cal_init(fe);
+
+		mutex_unlock(&priv->lock);
+	}
+
+	/* override default std map with values in config struct */
+	if ((cfg) && (cfg->std_map))
+		tda18271_update_std_map(fe, cfg->std_map);
+
+	mutex_unlock(&tda18271_list_mutex);
+
+	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	if (tda18271_debug & DBG_MAP)
+		tda18271_dump_std_map(fe);
+
+	return fe;
+fail:
+	mutex_unlock(&tda18271_list_mutex);
+
+	tda18271_release(fe);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(tda18271_attach);
+MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */

+ 212 - 0
drivers/media/dvb/frontends/tda18271-priv.h

@@ -0,0 +1,212 @@
+/*
+    tda18271-priv.h - private header for the NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; 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 __TDA18271_PRIV_H__
+#define __TDA18271_PRIV_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include "tda18271.h"
+
+#define R_ID     0x00	/* ID byte                */
+#define R_TM     0x01	/* Thermo byte            */
+#define R_PL     0x02	/* Power level byte       */
+#define R_EP1    0x03	/* Easy Prog byte 1       */
+#define R_EP2    0x04	/* Easy Prog byte 2       */
+#define R_EP3    0x05	/* Easy Prog byte 3       */
+#define R_EP4    0x06	/* Easy Prog byte 4       */
+#define R_EP5    0x07	/* Easy Prog byte 5       */
+#define R_CPD    0x08	/* Cal Post-Divider byte  */
+#define R_CD1    0x09	/* Cal Divider byte 1     */
+#define R_CD2    0x0a	/* Cal Divider byte 2     */
+#define R_CD3    0x0b	/* Cal Divider byte 3     */
+#define R_MPD    0x0c	/* Main Post-Divider byte */
+#define R_MD1    0x0d	/* Main Divider byte 1    */
+#define R_MD2    0x0e	/* Main Divider byte 2    */
+#define R_MD3    0x0f	/* Main Divider byte 3    */
+#define R_EB1    0x10	/* Extended byte 1        */
+#define R_EB2    0x11	/* Extended byte 2        */
+#define R_EB3    0x12	/* Extended byte 3        */
+#define R_EB4    0x13	/* Extended byte 4        */
+#define R_EB5    0x14	/* Extended byte 5        */
+#define R_EB6    0x15	/* Extended byte 6        */
+#define R_EB7    0x16	/* Extended byte 7        */
+#define R_EB8    0x17	/* Extended byte 8        */
+#define R_EB9    0x18	/* Extended byte 9        */
+#define R_EB10   0x19	/* Extended byte 10       */
+#define R_EB11   0x1a	/* Extended byte 11       */
+#define R_EB12   0x1b	/* Extended byte 12       */
+#define R_EB13   0x1c	/* Extended byte 13       */
+#define R_EB14   0x1d	/* Extended byte 14       */
+#define R_EB15   0x1e	/* Extended byte 15       */
+#define R_EB16   0x1f	/* Extended byte 16       */
+#define R_EB17   0x20	/* Extended byte 17       */
+#define R_EB18   0x21	/* Extended byte 18       */
+#define R_EB19   0x22	/* Extended byte 19       */
+#define R_EB20   0x23	/* Extended byte 20       */
+#define R_EB21   0x24	/* Extended byte 21       */
+#define R_EB22   0x25	/* Extended byte 22       */
+#define R_EB23   0x26	/* Extended byte 23       */
+
+#define TDA18271_NUM_REGS 39
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_rf_tracking_filter_cal {
+	u32 rfmax;
+	u8  rfband;
+	u32 rf1_def;
+	u32 rf2_def;
+	u32 rf3_def;
+	u32 rf1;
+	u32 rf2;
+	u32 rf3;
+	int rf_a1;
+	int rf_b1;
+	int rf_a2;
+	int rf_b2;
+};
+
+enum tda18271_mode {
+	TDA18271_ANALOG,
+	TDA18271_DIGITAL,
+};
+
+struct tda18271_map_layout;
+
+enum tda18271_ver {
+	TDA18271HDC1,
+	TDA18271HDC2,
+};
+
+struct tda18271_priv {
+	u8 i2c_addr;
+	struct i2c_adapter *i2c_adap;
+	unsigned char tda18271_regs[TDA18271_NUM_REGS];
+
+	struct list_head tda18271_list;
+
+	enum tda18271_mode mode;
+	enum tda18271_i2c_gate gate;
+	enum tda18271_ver id;
+
+	unsigned int count;
+	unsigned int tm_rfcal;
+	unsigned int cal_initialized:1;
+
+	struct tda18271_map_layout *maps;
+	struct tda18271_std_map std;
+	struct tda18271_rf_tracking_filter_cal rf_cal_state[8];
+
+	struct mutex lock;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+/*---------------------------------------------------------------------*/
+
+extern int tda18271_debug;
+
+#define DBG_INFO 1
+#define DBG_MAP  2
+#define DBG_REG  4
+#define DBG_ADV  8
+#define DBG_CAL  16
+
+#define tda_printk(kern, fmt, arg...) \
+	printk(kern "%s: " fmt, __FUNCTION__, ##arg)
+
+#define dprintk(kern, lvl, fmt, arg...) do {\
+	if (tda18271_debug & lvl) \
+		tda_printk(kern, fmt, ##arg); } while (0)
+
+#define tda_info(fmt, arg...) printk(KERN_INFO              fmt, ##arg)
+#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING,      fmt, ##arg)
+#define tda_err(fmt, arg...)  tda_printk(KERN_ERR,          fmt, ##arg)
+#define tda_dbg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg)
+#define tda_map(fmt, arg...)  dprintk(KERN_DEBUG, DBG_MAP,  fmt, ##arg)
+#define tda_reg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_REG,  fmt, ##arg)
+#define tda_cal(fmt, arg...)  dprintk(KERN_DEBUG, DBG_CAL,  fmt, ##arg)
+
+/*---------------------------------------------------------------------*/
+
+enum tda18271_map_type {
+	/* tda18271_pll_map */
+	MAIN_PLL,
+	CAL_PLL,
+	/* tda18271_map */
+	RF_CAL,
+	RF_CAL_KMCO,
+	RF_CAL_DC_OVER_DT,
+	BP_FILTER,
+	RF_BAND,
+	GAIN_TAPER,
+	IR_MEASURE,
+};
+
+extern int tda18271_lookup_pll_map(struct dvb_frontend *fe,
+				   enum tda18271_map_type map_type,
+				   u32 *freq, u8 *post_div, u8 *div);
+extern int tda18271_lookup_map(struct dvb_frontend *fe,
+			       enum tda18271_map_type map_type,
+			       u32 *freq, u8 *val);
+
+extern int tda18271_lookup_thermometer(struct dvb_frontend *fe);
+
+extern int tda18271_lookup_rf_band(struct dvb_frontend *fe,
+				   u32 *freq, u8 *rf_band);
+
+extern int tda18271_lookup_cid_target(struct dvb_frontend *fe,
+				      u32 *freq, u8 *cid_target,
+				      u16 *count_limit);
+
+extern int tda18271_assign_map_layout(struct dvb_frontend *fe);
+
+/*---------------------------------------------------------------------*/
+
+extern int tda18271_read_regs(struct dvb_frontend *fe);
+extern int tda18271_read_extended(struct dvb_frontend *fe);
+extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
+extern int tda18271_init_regs(struct dvb_frontend *fe);
+
+extern int tda18271_set_standby_mode(struct dvb_frontend *fe,
+				     int sm, int sm_lt, int sm_xt);
+
+extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq);
+extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq);
+
+extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq);
+
+#endif /* __TDA18271_PRIV_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */

+ 1285 - 0
drivers/media/dvb/frontends/tda18271-tables.c

@@ -0,0 +1,1285 @@
+/*
+    tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "tda18271-priv.h"
+
+struct tda18271_pll_map {
+	u32 lomax;
+	u8 pd; /* post div */
+	u8 d;  /*      div */
+};
+
+struct tda18271_map {
+	u32 rfmax;
+	u8  val;
+};
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_pll_map tda18271c1_main_pll[] = {
+	{ .lomax =  32000, .pd = 0x5f, .d = 0xf0 },
+	{ .lomax =  35000, .pd = 0x5e, .d = 0xe0 },
+	{ .lomax =  37000, .pd = 0x5d, .d = 0xd0 },
+	{ .lomax =  41000, .pd = 0x5c, .d = 0xc0 },
+	{ .lomax =  44000, .pd = 0x5b, .d = 0xb0 },
+	{ .lomax =  49000, .pd = 0x5a, .d = 0xa0 },
+	{ .lomax =  54000, .pd = 0x59, .d = 0x90 },
+	{ .lomax =  61000, .pd = 0x58, .d = 0x80 },
+	{ .lomax =  65000, .pd = 0x4f, .d = 0x78 },
+	{ .lomax =  70000, .pd = 0x4e, .d = 0x70 },
+	{ .lomax =  75000, .pd = 0x4d, .d = 0x68 },
+	{ .lomax =  82000, .pd = 0x4c, .d = 0x60 },
+	{ .lomax =  89000, .pd = 0x4b, .d = 0x58 },
+	{ .lomax =  98000, .pd = 0x4a, .d = 0x50 },
+	{ .lomax = 109000, .pd = 0x49, .d = 0x48 },
+	{ .lomax = 123000, .pd = 0x48, .d = 0x40 },
+	{ .lomax = 131000, .pd = 0x3f, .d = 0x3c },
+	{ .lomax = 141000, .pd = 0x3e, .d = 0x38 },
+	{ .lomax = 151000, .pd = 0x3d, .d = 0x34 },
+	{ .lomax = 164000, .pd = 0x3c, .d = 0x30 },
+	{ .lomax = 179000, .pd = 0x3b, .d = 0x2c },
+	{ .lomax = 197000, .pd = 0x3a, .d = 0x28 },
+	{ .lomax = 219000, .pd = 0x39, .d = 0x24 },
+	{ .lomax = 246000, .pd = 0x38, .d = 0x20 },
+	{ .lomax = 263000, .pd = 0x2f, .d = 0x1e },
+	{ .lomax = 282000, .pd = 0x2e, .d = 0x1c },
+	{ .lomax = 303000, .pd = 0x2d, .d = 0x1a },
+	{ .lomax = 329000, .pd = 0x2c, .d = 0x18 },
+	{ .lomax = 359000, .pd = 0x2b, .d = 0x16 },
+	{ .lomax = 395000, .pd = 0x2a, .d = 0x14 },
+	{ .lomax = 438000, .pd = 0x29, .d = 0x12 },
+	{ .lomax = 493000, .pd = 0x28, .d = 0x10 },
+	{ .lomax = 526000, .pd = 0x1f, .d = 0x0f },
+	{ .lomax = 564000, .pd = 0x1e, .d = 0x0e },
+	{ .lomax = 607000, .pd = 0x1d, .d = 0x0d },
+	{ .lomax = 658000, .pd = 0x1c, .d = 0x0c },
+	{ .lomax = 718000, .pd = 0x1b, .d = 0x0b },
+	{ .lomax = 790000, .pd = 0x1a, .d = 0x0a },
+	{ .lomax = 877000, .pd = 0x19, .d = 0x09 },
+	{ .lomax = 987000, .pd = 0x18, .d = 0x08 },
+	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c2_main_pll[] = {
+	{ .lomax =  33125, .pd = 0x57, .d = 0xf0 },
+	{ .lomax =  35500, .pd = 0x56, .d = 0xe0 },
+	{ .lomax =  38188, .pd = 0x55, .d = 0xd0 },
+	{ .lomax =  41375, .pd = 0x54, .d = 0xc0 },
+	{ .lomax =  45125, .pd = 0x53, .d = 0xb0 },
+	{ .lomax =  49688, .pd = 0x52, .d = 0xa0 },
+	{ .lomax =  55188, .pd = 0x51, .d = 0x90 },
+	{ .lomax =  62125, .pd = 0x50, .d = 0x80 },
+	{ .lomax =  66250, .pd = 0x47, .d = 0x78 },
+	{ .lomax =  71000, .pd = 0x46, .d = 0x70 },
+	{ .lomax =  76375, .pd = 0x45, .d = 0x68 },
+	{ .lomax =  82750, .pd = 0x44, .d = 0x60 },
+	{ .lomax =  90250, .pd = 0x43, .d = 0x58 },
+	{ .lomax =  99375, .pd = 0x42, .d = 0x50 },
+	{ .lomax = 110375, .pd = 0x41, .d = 0x48 },
+	{ .lomax = 124250, .pd = 0x40, .d = 0x40 },
+	{ .lomax = 132500, .pd = 0x37, .d = 0x3c },
+	{ .lomax = 142000, .pd = 0x36, .d = 0x38 },
+	{ .lomax = 152750, .pd = 0x35, .d = 0x34 },
+	{ .lomax = 165500, .pd = 0x34, .d = 0x30 },
+	{ .lomax = 180500, .pd = 0x33, .d = 0x2c },
+	{ .lomax = 198750, .pd = 0x32, .d = 0x28 },
+	{ .lomax = 220750, .pd = 0x31, .d = 0x24 },
+	{ .lomax = 248500, .pd = 0x30, .d = 0x20 },
+	{ .lomax = 265000, .pd = 0x27, .d = 0x1e },
+	{ .lomax = 284000, .pd = 0x26, .d = 0x1c },
+	{ .lomax = 305500, .pd = 0x25, .d = 0x1a },
+	{ .lomax = 331000, .pd = 0x24, .d = 0x18 },
+	{ .lomax = 361000, .pd = 0x23, .d = 0x16 },
+	{ .lomax = 397500, .pd = 0x22, .d = 0x14 },
+	{ .lomax = 441500, .pd = 0x21, .d = 0x12 },
+	{ .lomax = 497000, .pd = 0x20, .d = 0x10 },
+	{ .lomax = 530000, .pd = 0x17, .d = 0x0f },
+	{ .lomax = 568000, .pd = 0x16, .d = 0x0e },
+	{ .lomax = 611000, .pd = 0x15, .d = 0x0d },
+	{ .lomax = 662000, .pd = 0x14, .d = 0x0c },
+	{ .lomax = 722000, .pd = 0x13, .d = 0x0b },
+	{ .lomax = 795000, .pd = 0x12, .d = 0x0a },
+	{ .lomax = 883000, .pd = 0x11, .d = 0x09 },
+	{ .lomax = 994000, .pd = 0x10, .d = 0x08 },
+	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c1_cal_pll[] = {
+	{ .lomax =   33000, .pd = 0xdd, .d = 0xd0 },
+	{ .lomax =   36000, .pd = 0xdc, .d = 0xc0 },
+	{ .lomax =   40000, .pd = 0xdb, .d = 0xb0 },
+	{ .lomax =   44000, .pd = 0xda, .d = 0xa0 },
+	{ .lomax =   49000, .pd = 0xd9, .d = 0x90 },
+	{ .lomax =   55000, .pd = 0xd8, .d = 0x80 },
+	{ .lomax =   63000, .pd = 0xd3, .d = 0x70 },
+	{ .lomax =   67000, .pd = 0xcd, .d = 0x68 },
+	{ .lomax =   73000, .pd = 0xcc, .d = 0x60 },
+	{ .lomax =   80000, .pd = 0xcb, .d = 0x58 },
+	{ .lomax =   88000, .pd = 0xca, .d = 0x50 },
+	{ .lomax =   98000, .pd = 0xc9, .d = 0x48 },
+	{ .lomax =  110000, .pd = 0xc8, .d = 0x40 },
+	{ .lomax =  126000, .pd = 0xc3, .d = 0x38 },
+	{ .lomax =  135000, .pd = 0xbd, .d = 0x34 },
+	{ .lomax =  147000, .pd = 0xbc, .d = 0x30 },
+	{ .lomax =  160000, .pd = 0xbb, .d = 0x2c },
+	{ .lomax =  176000, .pd = 0xba, .d = 0x28 },
+	{ .lomax =  196000, .pd = 0xb9, .d = 0x24 },
+	{ .lomax =  220000, .pd = 0xb8, .d = 0x20 },
+	{ .lomax =  252000, .pd = 0xb3, .d = 0x1c },
+	{ .lomax =  271000, .pd = 0xad, .d = 0x1a },
+	{ .lomax =  294000, .pd = 0xac, .d = 0x18 },
+	{ .lomax =  321000, .pd = 0xab, .d = 0x16 },
+	{ .lomax =  353000, .pd = 0xaa, .d = 0x14 },
+	{ .lomax =  392000, .pd = 0xa9, .d = 0x12 },
+	{ .lomax =  441000, .pd = 0xa8, .d = 0x10 },
+	{ .lomax =  505000, .pd = 0xa3, .d = 0x0e },
+	{ .lomax =  543000, .pd = 0x9d, .d = 0x0d },
+	{ .lomax =  589000, .pd = 0x9c, .d = 0x0c },
+	{ .lomax =  642000, .pd = 0x9b, .d = 0x0b },
+	{ .lomax =  707000, .pd = 0x9a, .d = 0x0a },
+	{ .lomax =  785000, .pd = 0x99, .d = 0x09 },
+	{ .lomax =  883000, .pd = 0x98, .d = 0x08 },
+	{ .lomax = 1010000, .pd = 0x93, .d = 0x07 },
+	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c2_cal_pll[] = {
+	{ .lomax =   33813, .pd = 0xdd, .d = 0xd0 },
+	{ .lomax =   36625, .pd = 0xdc, .d = 0xc0 },
+	{ .lomax =   39938, .pd = 0xdb, .d = 0xb0 },
+	{ .lomax =   43938, .pd = 0xda, .d = 0xa0 },
+	{ .lomax =   48813, .pd = 0xd9, .d = 0x90 },
+	{ .lomax =   54938, .pd = 0xd8, .d = 0x80 },
+	{ .lomax =   62813, .pd = 0xd3, .d = 0x70 },
+	{ .lomax =   67625, .pd = 0xcd, .d = 0x68 },
+	{ .lomax =   73250, .pd = 0xcc, .d = 0x60 },
+	{ .lomax =   79875, .pd = 0xcb, .d = 0x58 },
+	{ .lomax =   87875, .pd = 0xca, .d = 0x50 },
+	{ .lomax =   97625, .pd = 0xc9, .d = 0x48 },
+	{ .lomax =  109875, .pd = 0xc8, .d = 0x40 },
+	{ .lomax =  125625, .pd = 0xc3, .d = 0x38 },
+	{ .lomax =  135250, .pd = 0xbd, .d = 0x34 },
+	{ .lomax =  146500, .pd = 0xbc, .d = 0x30 },
+	{ .lomax =  159750, .pd = 0xbb, .d = 0x2c },
+	{ .lomax =  175750, .pd = 0xba, .d = 0x28 },
+	{ .lomax =  195250, .pd = 0xb9, .d = 0x24 },
+	{ .lomax =  219750, .pd = 0xb8, .d = 0x20 },
+	{ .lomax =  251250, .pd = 0xb3, .d = 0x1c },
+	{ .lomax =  270500, .pd = 0xad, .d = 0x1a },
+	{ .lomax =  293000, .pd = 0xac, .d = 0x18 },
+	{ .lomax =  319500, .pd = 0xab, .d = 0x16 },
+	{ .lomax =  351500, .pd = 0xaa, .d = 0x14 },
+	{ .lomax =  390500, .pd = 0xa9, .d = 0x12 },
+	{ .lomax =  439500, .pd = 0xa8, .d = 0x10 },
+	{ .lomax =  502500, .pd = 0xa3, .d = 0x0e },
+	{ .lomax =  541000, .pd = 0x9d, .d = 0x0d },
+	{ .lomax =  586000, .pd = 0x9c, .d = 0x0c },
+	{ .lomax =  639000, .pd = 0x9b, .d = 0x0b },
+	{ .lomax =  703000, .pd = 0x9a, .d = 0x0a },
+	{ .lomax =  781000, .pd = 0x99, .d = 0x09 },
+	{ .lomax =  879000, .pd = 0x98, .d = 0x08 },
+	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_bp_filter[] = {
+	{ .rfmax =  62000, .val = 0x00 },
+	{ .rfmax =  84000, .val = 0x01 },
+	{ .rfmax = 100000, .val = 0x02 },
+	{ .rfmax = 140000, .val = 0x03 },
+	{ .rfmax = 170000, .val = 0x04 },
+	{ .rfmax = 180000, .val = 0x05 },
+	{ .rfmax = 865000, .val = 0x06 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c1_km[] = {
+	{ .rfmax =  61100, .val = 0x74 },
+	{ .rfmax = 350000, .val = 0x40 },
+	{ .rfmax = 720000, .val = 0x30 },
+	{ .rfmax = 865000, .val = 0x40 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c2_km[] = {
+	{ .rfmax =  47900, .val = 0x38 },
+	{ .rfmax =  61100, .val = 0x44 },
+	{ .rfmax = 350000, .val = 0x30 },
+	{ .rfmax = 720000, .val = 0x24 },
+	{ .rfmax = 865000, .val = 0x3c },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_rf_band[] = {
+	{ .rfmax =  47900, .val = 0x00 },
+	{ .rfmax =  61100, .val = 0x01 },
+/*	{ .rfmax = 152600, .val = 0x02 }, */
+	{ .rfmax = 121200, .val = 0x02 },
+	{ .rfmax = 164700, .val = 0x03 },
+	{ .rfmax = 203500, .val = 0x04 },
+	{ .rfmax = 457800, .val = 0x05 },
+	{ .rfmax = 865000, .val = 0x06 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_gain_taper[] = {
+	{ .rfmax =  45400, .val = 0x1f },
+	{ .rfmax =  45800, .val = 0x1e },
+	{ .rfmax =  46200, .val = 0x1d },
+	{ .rfmax =  46700, .val = 0x1c },
+	{ .rfmax =  47100, .val = 0x1b },
+	{ .rfmax =  47500, .val = 0x1a },
+	{ .rfmax =  47900, .val = 0x19 },
+	{ .rfmax =  49600, .val = 0x17 },
+	{ .rfmax =  51200, .val = 0x16 },
+	{ .rfmax =  52900, .val = 0x15 },
+	{ .rfmax =  54500, .val = 0x14 },
+	{ .rfmax =  56200, .val = 0x13 },
+	{ .rfmax =  57800, .val = 0x12 },
+	{ .rfmax =  59500, .val = 0x11 },
+	{ .rfmax =  61100, .val = 0x10 },
+	{ .rfmax =  67600, .val = 0x0d },
+	{ .rfmax =  74200, .val = 0x0c },
+	{ .rfmax =  80700, .val = 0x0b },
+	{ .rfmax =  87200, .val = 0x0a },
+	{ .rfmax =  93800, .val = 0x09 },
+	{ .rfmax = 100300, .val = 0x08 },
+	{ .rfmax = 106900, .val = 0x07 },
+	{ .rfmax = 113400, .val = 0x06 },
+	{ .rfmax = 119900, .val = 0x05 },
+	{ .rfmax = 126500, .val = 0x04 },
+	{ .rfmax = 133000, .val = 0x03 },
+	{ .rfmax = 139500, .val = 0x02 },
+	{ .rfmax = 146100, .val = 0x01 },
+	{ .rfmax = 152600, .val = 0x00 },
+	{ .rfmax = 154300, .val = 0x1f },
+	{ .rfmax = 156100, .val = 0x1e },
+	{ .rfmax = 157800, .val = 0x1d },
+	{ .rfmax = 159500, .val = 0x1c },
+	{ .rfmax = 161200, .val = 0x1b },
+	{ .rfmax = 163000, .val = 0x1a },
+	{ .rfmax = 164700, .val = 0x19 },
+	{ .rfmax = 170200, .val = 0x17 },
+	{ .rfmax = 175800, .val = 0x16 },
+	{ .rfmax = 181300, .val = 0x15 },
+	{ .rfmax = 186900, .val = 0x14 },
+	{ .rfmax = 192400, .val = 0x13 },
+	{ .rfmax = 198000, .val = 0x12 },
+	{ .rfmax = 203500, .val = 0x11 },
+	{ .rfmax = 216200, .val = 0x14 },
+	{ .rfmax = 228900, .val = 0x13 },
+	{ .rfmax = 241600, .val = 0x12 },
+	{ .rfmax = 254400, .val = 0x11 },
+	{ .rfmax = 267100, .val = 0x10 },
+	{ .rfmax = 279800, .val = 0x0f },
+	{ .rfmax = 292500, .val = 0x0e },
+	{ .rfmax = 305200, .val = 0x0d },
+	{ .rfmax = 317900, .val = 0x0c },
+	{ .rfmax = 330700, .val = 0x0b },
+	{ .rfmax = 343400, .val = 0x0a },
+	{ .rfmax = 356100, .val = 0x09 },
+	{ .rfmax = 368800, .val = 0x08 },
+	{ .rfmax = 381500, .val = 0x07 },
+	{ .rfmax = 394200, .val = 0x06 },
+	{ .rfmax = 406900, .val = 0x05 },
+	{ .rfmax = 419700, .val = 0x04 },
+	{ .rfmax = 432400, .val = 0x03 },
+	{ .rfmax = 445100, .val = 0x02 },
+	{ .rfmax = 457800, .val = 0x01 },
+	{ .rfmax = 476300, .val = 0x19 },
+	{ .rfmax = 494800, .val = 0x18 },
+	{ .rfmax = 513300, .val = 0x17 },
+	{ .rfmax = 531800, .val = 0x16 },
+	{ .rfmax = 550300, .val = 0x15 },
+	{ .rfmax = 568900, .val = 0x14 },
+	{ .rfmax = 587400, .val = 0x13 },
+	{ .rfmax = 605900, .val = 0x12 },
+	{ .rfmax = 624400, .val = 0x11 },
+	{ .rfmax = 642900, .val = 0x10 },
+	{ .rfmax = 661400, .val = 0x0f },
+	{ .rfmax = 679900, .val = 0x0e },
+	{ .rfmax = 698400, .val = 0x0d },
+	{ .rfmax = 716900, .val = 0x0c },
+	{ .rfmax = 735400, .val = 0x0b },
+	{ .rfmax = 753900, .val = 0x0a },
+	{ .rfmax = 772500, .val = 0x09 },
+	{ .rfmax = 791000, .val = 0x08 },
+	{ .rfmax = 809500, .val = 0x07 },
+	{ .rfmax = 828000, .val = 0x06 },
+	{ .rfmax = 846500, .val = 0x05 },
+	{ .rfmax = 865000, .val = 0x04 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c1_rf_cal[] = {
+	{ .rfmax = 41000, .val = 0x1e },
+	{ .rfmax = 43000, .val = 0x30 },
+	{ .rfmax = 45000, .val = 0x43 },
+	{ .rfmax = 46000, .val = 0x4d },
+	{ .rfmax = 47000, .val = 0x54 },
+	{ .rfmax = 47900, .val = 0x64 },
+	{ .rfmax = 49100, .val = 0x20 },
+	{ .rfmax = 50000, .val = 0x22 },
+	{ .rfmax = 51000, .val = 0x2a },
+	{ .rfmax = 53000, .val = 0x32 },
+	{ .rfmax = 55000, .val = 0x35 },
+	{ .rfmax = 56000, .val = 0x3c },
+	{ .rfmax = 57000, .val = 0x3f },
+	{ .rfmax = 58000, .val = 0x48 },
+	{ .rfmax = 59000, .val = 0x4d },
+	{ .rfmax = 60000, .val = 0x58 },
+	{ .rfmax = 61100, .val = 0x5f },
+	{ .rfmax =     0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c2_rf_cal[] = {
+	{ .rfmax =  41000, .val = 0x0f },
+	{ .rfmax =  43000, .val = 0x1c },
+	{ .rfmax =  45000, .val = 0x2f },
+	{ .rfmax =  46000, .val = 0x39 },
+	{ .rfmax =  47000, .val = 0x40 },
+	{ .rfmax =  47900, .val = 0x50 },
+	{ .rfmax =  49100, .val = 0x16 },
+	{ .rfmax =  50000, .val = 0x18 },
+	{ .rfmax =  51000, .val = 0x20 },
+	{ .rfmax =  53000, .val = 0x28 },
+	{ .rfmax =  55000, .val = 0x2b },
+	{ .rfmax =  56000, .val = 0x32 },
+	{ .rfmax =  57000, .val = 0x35 },
+	{ .rfmax =  58000, .val = 0x3e },
+	{ .rfmax =  59000, .val = 0x43 },
+	{ .rfmax =  60000, .val = 0x4e },
+	{ .rfmax =  61100, .val = 0x55 },
+	{ .rfmax =  63000, .val = 0x0f },
+	{ .rfmax =  64000, .val = 0x11 },
+	{ .rfmax =  65000, .val = 0x12 },
+	{ .rfmax =  66000, .val = 0x15 },
+	{ .rfmax =  67000, .val = 0x16 },
+	{ .rfmax =  68000, .val = 0x17 },
+	{ .rfmax =  70000, .val = 0x19 },
+	{ .rfmax =  71000, .val = 0x1c },
+	{ .rfmax =  72000, .val = 0x1d },
+	{ .rfmax =  73000, .val = 0x1f },
+	{ .rfmax =  74000, .val = 0x20 },
+	{ .rfmax =  75000, .val = 0x21 },
+	{ .rfmax =  76000, .val = 0x24 },
+	{ .rfmax =  77000, .val = 0x25 },
+	{ .rfmax =  78000, .val = 0x27 },
+	{ .rfmax =  80000, .val = 0x28 },
+	{ .rfmax =  81000, .val = 0x29 },
+	{ .rfmax =  82000, .val = 0x2d },
+	{ .rfmax =  83000, .val = 0x2e },
+	{ .rfmax =  84000, .val = 0x2f },
+	{ .rfmax =  85000, .val = 0x31 },
+	{ .rfmax =  86000, .val = 0x33 },
+	{ .rfmax =  87000, .val = 0x34 },
+	{ .rfmax =  88000, .val = 0x35 },
+	{ .rfmax =  89000, .val = 0x37 },
+	{ .rfmax =  90000, .val = 0x38 },
+	{ .rfmax =  91000, .val = 0x39 },
+	{ .rfmax =  93000, .val = 0x3c },
+	{ .rfmax =  94000, .val = 0x3e },
+	{ .rfmax =  95000, .val = 0x3f },
+	{ .rfmax =  96000, .val = 0x40 },
+	{ .rfmax =  97000, .val = 0x42 },
+	{ .rfmax =  99000, .val = 0x45 },
+	{ .rfmax = 100000, .val = 0x46 },
+	{ .rfmax = 102000, .val = 0x48 },
+	{ .rfmax = 103000, .val = 0x4a },
+	{ .rfmax = 105000, .val = 0x4d },
+	{ .rfmax = 106000, .val = 0x4e },
+	{ .rfmax = 107000, .val = 0x50 },
+	{ .rfmax = 108000, .val = 0x51 },
+	{ .rfmax = 110000, .val = 0x54 },
+	{ .rfmax = 111000, .val = 0x56 },
+	{ .rfmax = 112000, .val = 0x57 },
+	{ .rfmax = 113000, .val = 0x58 },
+	{ .rfmax = 114000, .val = 0x59 },
+	{ .rfmax = 115000, .val = 0x5c },
+	{ .rfmax = 116000, .val = 0x5d },
+	{ .rfmax = 117000, .val = 0x5f },
+	{ .rfmax = 119000, .val = 0x60 },
+	{ .rfmax = 120000, .val = 0x64 },
+	{ .rfmax = 121000, .val = 0x65 },
+	{ .rfmax = 122000, .val = 0x66 },
+	{ .rfmax = 123000, .val = 0x68 },
+	{ .rfmax = 124000, .val = 0x69 },
+	{ .rfmax = 125000, .val = 0x6c },
+	{ .rfmax = 126000, .val = 0x6d },
+	{ .rfmax = 127000, .val = 0x6e },
+	{ .rfmax = 128000, .val = 0x70 },
+	{ .rfmax = 129000, .val = 0x71 },
+	{ .rfmax = 130000, .val = 0x75 },
+	{ .rfmax = 131000, .val = 0x77 },
+	{ .rfmax = 132000, .val = 0x78 },
+	{ .rfmax = 133000, .val = 0x7b },
+	{ .rfmax = 134000, .val = 0x7e },
+	{ .rfmax = 135000, .val = 0x81 },
+	{ .rfmax = 136000, .val = 0x82 },
+	{ .rfmax = 137000, .val = 0x87 },
+	{ .rfmax = 138000, .val = 0x88 },
+	{ .rfmax = 139000, .val = 0x8d },
+	{ .rfmax = 140000, .val = 0x8e },
+	{ .rfmax = 141000, .val = 0x91 },
+	{ .rfmax = 142000, .val = 0x95 },
+	{ .rfmax = 143000, .val = 0x9a },
+	{ .rfmax = 144000, .val = 0x9d },
+	{ .rfmax = 145000, .val = 0xa1 },
+	{ .rfmax = 146000, .val = 0xa2 },
+	{ .rfmax = 147000, .val = 0xa4 },
+	{ .rfmax = 148000, .val = 0xa9 },
+	{ .rfmax = 149000, .val = 0xae },
+	{ .rfmax = 150000, .val = 0xb0 },
+	{ .rfmax = 151000, .val = 0xb1 },
+	{ .rfmax = 152000, .val = 0xb7 },
+	{ .rfmax = 153000, .val = 0xbd },
+	{ .rfmax = 154000, .val = 0x20 },
+	{ .rfmax = 155000, .val = 0x22 },
+	{ .rfmax = 156000, .val = 0x24 },
+	{ .rfmax = 157000, .val = 0x25 },
+	{ .rfmax = 158000, .val = 0x27 },
+	{ .rfmax = 159000, .val = 0x29 },
+	{ .rfmax = 160000, .val = 0x2c },
+	{ .rfmax = 161000, .val = 0x2d },
+	{ .rfmax = 163000, .val = 0x2e },
+	{ .rfmax = 164000, .val = 0x2f },
+	{ .rfmax = 165000, .val = 0x30 },
+	{ .rfmax = 166000, .val = 0x11 },
+	{ .rfmax = 167000, .val = 0x12 },
+	{ .rfmax = 168000, .val = 0x13 },
+	{ .rfmax = 169000, .val = 0x14 },
+	{ .rfmax = 170000, .val = 0x15 },
+	{ .rfmax = 172000, .val = 0x16 },
+	{ .rfmax = 173000, .val = 0x17 },
+	{ .rfmax = 174000, .val = 0x18 },
+	{ .rfmax = 175000, .val = 0x1a },
+	{ .rfmax = 176000, .val = 0x1b },
+	{ .rfmax = 178000, .val = 0x1d },
+	{ .rfmax = 179000, .val = 0x1e },
+	{ .rfmax = 180000, .val = 0x1f },
+	{ .rfmax = 181000, .val = 0x20 },
+	{ .rfmax = 182000, .val = 0x21 },
+	{ .rfmax = 183000, .val = 0x22 },
+	{ .rfmax = 184000, .val = 0x24 },
+	{ .rfmax = 185000, .val = 0x25 },
+	{ .rfmax = 186000, .val = 0x26 },
+	{ .rfmax = 187000, .val = 0x27 },
+	{ .rfmax = 188000, .val = 0x29 },
+	{ .rfmax = 189000, .val = 0x2a },
+	{ .rfmax = 190000, .val = 0x2c },
+	{ .rfmax = 191000, .val = 0x2d },
+	{ .rfmax = 192000, .val = 0x2e },
+	{ .rfmax = 193000, .val = 0x2f },
+	{ .rfmax = 194000, .val = 0x30 },
+	{ .rfmax = 195000, .val = 0x33 },
+	{ .rfmax = 196000, .val = 0x35 },
+	{ .rfmax = 198000, .val = 0x36 },
+	{ .rfmax = 200000, .val = 0x38 },
+	{ .rfmax = 201000, .val = 0x3c },
+	{ .rfmax = 202000, .val = 0x3d },
+	{ .rfmax = 203500, .val = 0x3e },
+	{ .rfmax = 206000, .val = 0x0e },
+	{ .rfmax = 208000, .val = 0x0f },
+	{ .rfmax = 212000, .val = 0x10 },
+	{ .rfmax = 216000, .val = 0x11 },
+	{ .rfmax = 217000, .val = 0x12 },
+	{ .rfmax = 218000, .val = 0x13 },
+	{ .rfmax = 220000, .val = 0x14 },
+	{ .rfmax = 222000, .val = 0x15 },
+	{ .rfmax = 225000, .val = 0x16 },
+	{ .rfmax = 228000, .val = 0x17 },
+	{ .rfmax = 231000, .val = 0x18 },
+	{ .rfmax = 234000, .val = 0x19 },
+	{ .rfmax = 235000, .val = 0x1a },
+	{ .rfmax = 236000, .val = 0x1b },
+	{ .rfmax = 237000, .val = 0x1c },
+	{ .rfmax = 240000, .val = 0x1d },
+	{ .rfmax = 242000, .val = 0x1f },
+	{ .rfmax = 247000, .val = 0x20 },
+	{ .rfmax = 249000, .val = 0x21 },
+	{ .rfmax = 252000, .val = 0x22 },
+	{ .rfmax = 253000, .val = 0x23 },
+	{ .rfmax = 254000, .val = 0x24 },
+	{ .rfmax = 256000, .val = 0x25 },
+	{ .rfmax = 259000, .val = 0x26 },
+	{ .rfmax = 262000, .val = 0x27 },
+	{ .rfmax = 264000, .val = 0x28 },
+	{ .rfmax = 267000, .val = 0x29 },
+	{ .rfmax = 269000, .val = 0x2a },
+	{ .rfmax = 271000, .val = 0x2b },
+	{ .rfmax = 273000, .val = 0x2c },
+	{ .rfmax = 275000, .val = 0x2d },
+	{ .rfmax = 277000, .val = 0x2e },
+	{ .rfmax = 279000, .val = 0x2f },
+	{ .rfmax = 282000, .val = 0x30 },
+	{ .rfmax = 284000, .val = 0x31 },
+	{ .rfmax = 286000, .val = 0x32 },
+	{ .rfmax = 287000, .val = 0x33 },
+	{ .rfmax = 290000, .val = 0x34 },
+	{ .rfmax = 293000, .val = 0x35 },
+	{ .rfmax = 295000, .val = 0x36 },
+	{ .rfmax = 297000, .val = 0x37 },
+	{ .rfmax = 300000, .val = 0x38 },
+	{ .rfmax = 303000, .val = 0x39 },
+	{ .rfmax = 305000, .val = 0x3a },
+	{ .rfmax = 306000, .val = 0x3b },
+	{ .rfmax = 307000, .val = 0x3c },
+	{ .rfmax = 310000, .val = 0x3d },
+	{ .rfmax = 312000, .val = 0x3e },
+	{ .rfmax = 315000, .val = 0x3f },
+	{ .rfmax = 318000, .val = 0x40 },
+	{ .rfmax = 320000, .val = 0x41 },
+	{ .rfmax = 323000, .val = 0x42 },
+	{ .rfmax = 324000, .val = 0x43 },
+	{ .rfmax = 325000, .val = 0x44 },
+	{ .rfmax = 327000, .val = 0x45 },
+	{ .rfmax = 331000, .val = 0x46 },
+	{ .rfmax = 334000, .val = 0x47 },
+	{ .rfmax = 337000, .val = 0x48 },
+	{ .rfmax = 339000, .val = 0x49 },
+	{ .rfmax = 340000, .val = 0x4a },
+	{ .rfmax = 341000, .val = 0x4b },
+	{ .rfmax = 343000, .val = 0x4c },
+	{ .rfmax = 345000, .val = 0x4d },
+	{ .rfmax = 349000, .val = 0x4e },
+	{ .rfmax = 352000, .val = 0x4f },
+	{ .rfmax = 353000, .val = 0x50 },
+	{ .rfmax = 355000, .val = 0x51 },
+	{ .rfmax = 357000, .val = 0x52 },
+	{ .rfmax = 359000, .val = 0x53 },
+	{ .rfmax = 361000, .val = 0x54 },
+	{ .rfmax = 362000, .val = 0x55 },
+	{ .rfmax = 364000, .val = 0x56 },
+	{ .rfmax = 368000, .val = 0x57 },
+	{ .rfmax = 370000, .val = 0x58 },
+	{ .rfmax = 372000, .val = 0x59 },
+	{ .rfmax = 375000, .val = 0x5a },
+	{ .rfmax = 376000, .val = 0x5b },
+	{ .rfmax = 377000, .val = 0x5c },
+	{ .rfmax = 379000, .val = 0x5d },
+	{ .rfmax = 382000, .val = 0x5e },
+	{ .rfmax = 384000, .val = 0x5f },
+	{ .rfmax = 385000, .val = 0x60 },
+	{ .rfmax = 386000, .val = 0x61 },
+	{ .rfmax = 388000, .val = 0x62 },
+	{ .rfmax = 390000, .val = 0x63 },
+	{ .rfmax = 393000, .val = 0x64 },
+	{ .rfmax = 394000, .val = 0x65 },
+	{ .rfmax = 396000, .val = 0x66 },
+	{ .rfmax = 397000, .val = 0x67 },
+	{ .rfmax = 398000, .val = 0x68 },
+	{ .rfmax = 400000, .val = 0x69 },
+	{ .rfmax = 402000, .val = 0x6a },
+	{ .rfmax = 403000, .val = 0x6b },
+	{ .rfmax = 407000, .val = 0x6c },
+	{ .rfmax = 408000, .val = 0x6d },
+	{ .rfmax = 409000, .val = 0x6e },
+	{ .rfmax = 410000, .val = 0x6f },
+	{ .rfmax = 411000, .val = 0x70 },
+	{ .rfmax = 412000, .val = 0x71 },
+	{ .rfmax = 413000, .val = 0x72 },
+	{ .rfmax = 414000, .val = 0x73 },
+	{ .rfmax = 417000, .val = 0x74 },
+	{ .rfmax = 418000, .val = 0x75 },
+	{ .rfmax = 420000, .val = 0x76 },
+	{ .rfmax = 422000, .val = 0x77 },
+	{ .rfmax = 423000, .val = 0x78 },
+	{ .rfmax = 424000, .val = 0x79 },
+	{ .rfmax = 427000, .val = 0x7a },
+	{ .rfmax = 428000, .val = 0x7b },
+	{ .rfmax = 429000, .val = 0x7d },
+	{ .rfmax = 432000, .val = 0x7f },
+	{ .rfmax = 434000, .val = 0x80 },
+	{ .rfmax = 435000, .val = 0x81 },
+	{ .rfmax = 436000, .val = 0x83 },
+	{ .rfmax = 437000, .val = 0x84 },
+	{ .rfmax = 438000, .val = 0x85 },
+	{ .rfmax = 439000, .val = 0x86 },
+	{ .rfmax = 440000, .val = 0x87 },
+	{ .rfmax = 441000, .val = 0x88 },
+	{ .rfmax = 442000, .val = 0x89 },
+	{ .rfmax = 445000, .val = 0x8a },
+	{ .rfmax = 446000, .val = 0x8b },
+	{ .rfmax = 447000, .val = 0x8c },
+	{ .rfmax = 448000, .val = 0x8e },
+	{ .rfmax = 449000, .val = 0x8f },
+	{ .rfmax = 450000, .val = 0x90 },
+	{ .rfmax = 452000, .val = 0x91 },
+	{ .rfmax = 453000, .val = 0x93 },
+	{ .rfmax = 454000, .val = 0x94 },
+	{ .rfmax = 456000, .val = 0x96 },
+	{ .rfmax = 457000, .val = 0x98 },
+	{ .rfmax = 461000, .val = 0x11 },
+	{ .rfmax = 468000, .val = 0x12 },
+	{ .rfmax = 472000, .val = 0x13 },
+	{ .rfmax = 473000, .val = 0x14 },
+	{ .rfmax = 474000, .val = 0x15 },
+	{ .rfmax = 481000, .val = 0x16 },
+	{ .rfmax = 486000, .val = 0x17 },
+	{ .rfmax = 491000, .val = 0x18 },
+	{ .rfmax = 498000, .val = 0x19 },
+	{ .rfmax = 499000, .val = 0x1a },
+	{ .rfmax = 501000, .val = 0x1b },
+	{ .rfmax = 506000, .val = 0x1c },
+	{ .rfmax = 511000, .val = 0x1d },
+	{ .rfmax = 516000, .val = 0x1e },
+	{ .rfmax = 520000, .val = 0x1f },
+	{ .rfmax = 521000, .val = 0x20 },
+	{ .rfmax = 525000, .val = 0x21 },
+	{ .rfmax = 529000, .val = 0x22 },
+	{ .rfmax = 533000, .val = 0x23 },
+	{ .rfmax = 539000, .val = 0x24 },
+	{ .rfmax = 541000, .val = 0x25 },
+	{ .rfmax = 547000, .val = 0x26 },
+	{ .rfmax = 549000, .val = 0x27 },
+	{ .rfmax = 551000, .val = 0x28 },
+	{ .rfmax = 556000, .val = 0x29 },
+	{ .rfmax = 561000, .val = 0x2a },
+	{ .rfmax = 563000, .val = 0x2b },
+	{ .rfmax = 565000, .val = 0x2c },
+	{ .rfmax = 569000, .val = 0x2d },
+	{ .rfmax = 571000, .val = 0x2e },
+	{ .rfmax = 577000, .val = 0x2f },
+	{ .rfmax = 580000, .val = 0x30 },
+	{ .rfmax = 582000, .val = 0x31 },
+	{ .rfmax = 584000, .val = 0x32 },
+	{ .rfmax = 588000, .val = 0x33 },
+	{ .rfmax = 591000, .val = 0x34 },
+	{ .rfmax = 596000, .val = 0x35 },
+	{ .rfmax = 598000, .val = 0x36 },
+	{ .rfmax = 603000, .val = 0x37 },
+	{ .rfmax = 604000, .val = 0x38 },
+	{ .rfmax = 606000, .val = 0x39 },
+	{ .rfmax = 612000, .val = 0x3a },
+	{ .rfmax = 615000, .val = 0x3b },
+	{ .rfmax = 617000, .val = 0x3c },
+	{ .rfmax = 621000, .val = 0x3d },
+	{ .rfmax = 622000, .val = 0x3e },
+	{ .rfmax = 625000, .val = 0x3f },
+	{ .rfmax = 632000, .val = 0x40 },
+	{ .rfmax = 633000, .val = 0x41 },
+	{ .rfmax = 634000, .val = 0x42 },
+	{ .rfmax = 642000, .val = 0x43 },
+	{ .rfmax = 643000, .val = 0x44 },
+	{ .rfmax = 647000, .val = 0x45 },
+	{ .rfmax = 650000, .val = 0x46 },
+	{ .rfmax = 652000, .val = 0x47 },
+	{ .rfmax = 657000, .val = 0x48 },
+	{ .rfmax = 661000, .val = 0x49 },
+	{ .rfmax = 662000, .val = 0x4a },
+	{ .rfmax = 665000, .val = 0x4b },
+	{ .rfmax = 667000, .val = 0x4c },
+	{ .rfmax = 670000, .val = 0x4d },
+	{ .rfmax = 673000, .val = 0x4e },
+	{ .rfmax = 676000, .val = 0x4f },
+	{ .rfmax = 677000, .val = 0x50 },
+	{ .rfmax = 681000, .val = 0x51 },
+	{ .rfmax = 683000, .val = 0x52 },
+	{ .rfmax = 686000, .val = 0x53 },
+	{ .rfmax = 688000, .val = 0x54 },
+	{ .rfmax = 689000, .val = 0x55 },
+	{ .rfmax = 691000, .val = 0x56 },
+	{ .rfmax = 695000, .val = 0x57 },
+	{ .rfmax = 698000, .val = 0x58 },
+	{ .rfmax = 703000, .val = 0x59 },
+	{ .rfmax = 704000, .val = 0x5a },
+	{ .rfmax = 705000, .val = 0x5b },
+	{ .rfmax = 707000, .val = 0x5c },
+	{ .rfmax = 710000, .val = 0x5d },
+	{ .rfmax = 712000, .val = 0x5e },
+	{ .rfmax = 717000, .val = 0x5f },
+	{ .rfmax = 718000, .val = 0x60 },
+	{ .rfmax = 721000, .val = 0x61 },
+	{ .rfmax = 722000, .val = 0x62 },
+	{ .rfmax = 723000, .val = 0x63 },
+	{ .rfmax = 725000, .val = 0x64 },
+	{ .rfmax = 727000, .val = 0x65 },
+	{ .rfmax = 730000, .val = 0x66 },
+	{ .rfmax = 732000, .val = 0x67 },
+	{ .rfmax = 735000, .val = 0x68 },
+	{ .rfmax = 740000, .val = 0x69 },
+	{ .rfmax = 741000, .val = 0x6a },
+	{ .rfmax = 742000, .val = 0x6b },
+	{ .rfmax = 743000, .val = 0x6c },
+	{ .rfmax = 745000, .val = 0x6d },
+	{ .rfmax = 747000, .val = 0x6e },
+	{ .rfmax = 748000, .val = 0x6f },
+	{ .rfmax = 750000, .val = 0x70 },
+	{ .rfmax = 752000, .val = 0x71 },
+	{ .rfmax = 754000, .val = 0x72 },
+	{ .rfmax = 757000, .val = 0x73 },
+	{ .rfmax = 758000, .val = 0x74 },
+	{ .rfmax = 760000, .val = 0x75 },
+	{ .rfmax = 763000, .val = 0x76 },
+	{ .rfmax = 764000, .val = 0x77 },
+	{ .rfmax = 766000, .val = 0x78 },
+	{ .rfmax = 767000, .val = 0x79 },
+	{ .rfmax = 768000, .val = 0x7a },
+	{ .rfmax = 773000, .val = 0x7b },
+	{ .rfmax = 774000, .val = 0x7c },
+	{ .rfmax = 776000, .val = 0x7d },
+	{ .rfmax = 777000, .val = 0x7e },
+	{ .rfmax = 778000, .val = 0x7f },
+	{ .rfmax = 779000, .val = 0x80 },
+	{ .rfmax = 781000, .val = 0x81 },
+	{ .rfmax = 783000, .val = 0x82 },
+	{ .rfmax = 784000, .val = 0x83 },
+	{ .rfmax = 785000, .val = 0x84 },
+	{ .rfmax = 786000, .val = 0x85 },
+	{ .rfmax = 793000, .val = 0x86 },
+	{ .rfmax = 794000, .val = 0x87 },
+	{ .rfmax = 795000, .val = 0x88 },
+	{ .rfmax = 797000, .val = 0x89 },
+	{ .rfmax = 799000, .val = 0x8a },
+	{ .rfmax = 801000, .val = 0x8b },
+	{ .rfmax = 802000, .val = 0x8c },
+	{ .rfmax = 803000, .val = 0x8d },
+	{ .rfmax = 804000, .val = 0x8e },
+	{ .rfmax = 810000, .val = 0x90 },
+	{ .rfmax = 811000, .val = 0x91 },
+	{ .rfmax = 812000, .val = 0x92 },
+	{ .rfmax = 814000, .val = 0x93 },
+	{ .rfmax = 816000, .val = 0x94 },
+	{ .rfmax = 817000, .val = 0x96 },
+	{ .rfmax = 818000, .val = 0x97 },
+	{ .rfmax = 820000, .val = 0x98 },
+	{ .rfmax = 821000, .val = 0x99 },
+	{ .rfmax = 822000, .val = 0x9a },
+	{ .rfmax = 828000, .val = 0x9b },
+	{ .rfmax = 829000, .val = 0x9d },
+	{ .rfmax = 830000, .val = 0x9f },
+	{ .rfmax = 831000, .val = 0xa0 },
+	{ .rfmax = 833000, .val = 0xa1 },
+	{ .rfmax = 835000, .val = 0xa2 },
+	{ .rfmax = 836000, .val = 0xa3 },
+	{ .rfmax = 837000, .val = 0xa4 },
+	{ .rfmax = 838000, .val = 0xa6 },
+	{ .rfmax = 840000, .val = 0xa8 },
+	{ .rfmax = 842000, .val = 0xa9 },
+	{ .rfmax = 845000, .val = 0xaa },
+	{ .rfmax = 846000, .val = 0xab },
+	{ .rfmax = 847000, .val = 0xad },
+	{ .rfmax = 848000, .val = 0xae },
+	{ .rfmax = 852000, .val = 0xaf },
+	{ .rfmax = 853000, .val = 0xb0 },
+	{ .rfmax = 858000, .val = 0xb1 },
+	{ .rfmax = 860000, .val = 0xb2 },
+	{ .rfmax = 861000, .val = 0xb3 },
+	{ .rfmax = 862000, .val = 0xb4 },
+	{ .rfmax = 863000, .val = 0xb6 },
+	{ .rfmax = 864000, .val = 0xb8 },
+	{ .rfmax = 865000, .val = 0xb9 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_ir_measure[] = {
+	{ .rfmax =  30000, .val = 4 },
+	{ .rfmax = 200000, .val = 5 },
+	{ .rfmax = 600000, .val = 6 },
+	{ .rfmax = 865000, .val = 7 },
+	{ .rfmax =      0, .val = 0 }, /* end */
+};
+
+static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = {
+	{ .rfmax =  47900, .val = 0x00 },
+	{ .rfmax =  55000, .val = 0x00 },
+	{ .rfmax =  61100, .val = 0x0a },
+	{ .rfmax =  64000, .val = 0x0a },
+	{ .rfmax =  82000, .val = 0x14 },
+	{ .rfmax =  84000, .val = 0x19 },
+	{ .rfmax = 119000, .val = 0x1c },
+	{ .rfmax = 124000, .val = 0x20 },
+	{ .rfmax = 129000, .val = 0x2a },
+	{ .rfmax = 134000, .val = 0x32 },
+	{ .rfmax = 139000, .val = 0x39 },
+	{ .rfmax = 144000, .val = 0x3e },
+	{ .rfmax = 149000, .val = 0x3f },
+	{ .rfmax = 152600, .val = 0x40 },
+	{ .rfmax = 154000, .val = 0x40 },
+	{ .rfmax = 164700, .val = 0x41 },
+	{ .rfmax = 203500, .val = 0x32 },
+	{ .rfmax = 353000, .val = 0x19 },
+	{ .rfmax = 356000, .val = 0x1a },
+	{ .rfmax = 359000, .val = 0x1b },
+	{ .rfmax = 363000, .val = 0x1c },
+	{ .rfmax = 366000, .val = 0x1d },
+	{ .rfmax = 369000, .val = 0x1e },
+	{ .rfmax = 373000, .val = 0x1f },
+	{ .rfmax = 376000, .val = 0x20 },
+	{ .rfmax = 379000, .val = 0x21 },
+	{ .rfmax = 383000, .val = 0x22 },
+	{ .rfmax = 386000, .val = 0x23 },
+	{ .rfmax = 389000, .val = 0x24 },
+	{ .rfmax = 393000, .val = 0x25 },
+	{ .rfmax = 396000, .val = 0x26 },
+	{ .rfmax = 399000, .val = 0x27 },
+	{ .rfmax = 402000, .val = 0x28 },
+	{ .rfmax = 404000, .val = 0x29 },
+	{ .rfmax = 407000, .val = 0x2a },
+	{ .rfmax = 409000, .val = 0x2b },
+	{ .rfmax = 412000, .val = 0x2c },
+	{ .rfmax = 414000, .val = 0x2d },
+	{ .rfmax = 417000, .val = 0x2e },
+	{ .rfmax = 419000, .val = 0x2f },
+	{ .rfmax = 422000, .val = 0x30 },
+	{ .rfmax = 424000, .val = 0x31 },
+	{ .rfmax = 427000, .val = 0x32 },
+	{ .rfmax = 429000, .val = 0x33 },
+	{ .rfmax = 432000, .val = 0x34 },
+	{ .rfmax = 434000, .val = 0x35 },
+	{ .rfmax = 437000, .val = 0x36 },
+	{ .rfmax = 439000, .val = 0x37 },
+	{ .rfmax = 442000, .val = 0x38 },
+	{ .rfmax = 444000, .val = 0x39 },
+	{ .rfmax = 447000, .val = 0x3a },
+	{ .rfmax = 449000, .val = 0x3b },
+	{ .rfmax = 457800, .val = 0x3c },
+	{ .rfmax = 465000, .val = 0x0f },
+	{ .rfmax = 477000, .val = 0x12 },
+	{ .rfmax = 483000, .val = 0x14 },
+	{ .rfmax = 502000, .val = 0x19 },
+	{ .rfmax = 508000, .val = 0x1b },
+	{ .rfmax = 519000, .val = 0x1c },
+	{ .rfmax = 522000, .val = 0x1d },
+	{ .rfmax = 524000, .val = 0x1e },
+	{ .rfmax = 534000, .val = 0x1f },
+	{ .rfmax = 549000, .val = 0x20 },
+	{ .rfmax = 554000, .val = 0x22 },
+	{ .rfmax = 584000, .val = 0x24 },
+	{ .rfmax = 589000, .val = 0x26 },
+	{ .rfmax = 658000, .val = 0x27 },
+	{ .rfmax = 664000, .val = 0x2c },
+	{ .rfmax = 669000, .val = 0x2d },
+	{ .rfmax = 699000, .val = 0x2e },
+	{ .rfmax = 704000, .val = 0x30 },
+	{ .rfmax = 709000, .val = 0x31 },
+	{ .rfmax = 714000, .val = 0x32 },
+	{ .rfmax = 724000, .val = 0x33 },
+	{ .rfmax = 729000, .val = 0x36 },
+	{ .rfmax = 739000, .val = 0x38 },
+	{ .rfmax = 744000, .val = 0x39 },
+	{ .rfmax = 749000, .val = 0x3b },
+	{ .rfmax = 754000, .val = 0x3c },
+	{ .rfmax = 759000, .val = 0x3d },
+	{ .rfmax = 764000, .val = 0x3e },
+	{ .rfmax = 769000, .val = 0x3f },
+	{ .rfmax = 774000, .val = 0x40 },
+	{ .rfmax = 779000, .val = 0x41 },
+	{ .rfmax = 784000, .val = 0x43 },
+	{ .rfmax = 789000, .val = 0x46 },
+	{ .rfmax = 794000, .val = 0x48 },
+	{ .rfmax = 799000, .val = 0x4b },
+	{ .rfmax = 804000, .val = 0x4f },
+	{ .rfmax = 809000, .val = 0x54 },
+	{ .rfmax = 814000, .val = 0x59 },
+	{ .rfmax = 819000, .val = 0x5d },
+	{ .rfmax = 824000, .val = 0x61 },
+	{ .rfmax = 829000, .val = 0x68 },
+	{ .rfmax = 834000, .val = 0x6e },
+	{ .rfmax = 839000, .val = 0x75 },
+	{ .rfmax = 844000, .val = 0x7e },
+	{ .rfmax = 849000, .val = 0x82 },
+	{ .rfmax = 854000, .val = 0x84 },
+	{ .rfmax = 859000, .val = 0x8f },
+	{ .rfmax = 865000, .val = 0x9a },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_thermo_map {
+	u8 d;
+	u8 r0;
+	u8 r1;
+};
+
+static struct tda18271_thermo_map tda18271_thermometer[] = {
+	{ .d = 0x00, .r0 = 60, .r1 =  92 },
+	{ .d = 0x01, .r0 = 62, .r1 =  94 },
+	{ .d = 0x02, .r0 = 66, .r1 =  98 },
+	{ .d = 0x03, .r0 = 64, .r1 =  96 },
+	{ .d = 0x04, .r0 = 74, .r1 = 106 },
+	{ .d = 0x05, .r0 = 72, .r1 = 104 },
+	{ .d = 0x06, .r0 = 68, .r1 = 100 },
+	{ .d = 0x07, .r0 = 70, .r1 = 102 },
+	{ .d = 0x08, .r0 = 90, .r1 = 122 },
+	{ .d = 0x09, .r0 = 88, .r1 = 120 },
+	{ .d = 0x0a, .r0 = 84, .r1 = 116 },
+	{ .d = 0x0b, .r0 = 86, .r1 = 118 },
+	{ .d = 0x0c, .r0 = 76, .r1 = 108 },
+	{ .d = 0x0d, .r0 = 78, .r1 = 110 },
+	{ .d = 0x0e, .r0 = 82, .r1 = 114 },
+	{ .d = 0x0f, .r0 = 80, .r1 = 112 },
+	{ .d = 0x00, .r0 =  0, .r1 =   0 }, /* end */
+};
+
+int tda18271_lookup_thermometer(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int val, i = 0;
+
+	while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) {
+		if (tda18271_thermometer[i + 1].d == 0)
+			break;
+		i++;
+	}
+
+	if ((regs[R_TM] & 0x20) == 0x20)
+		val = tda18271_thermometer[i].r1;
+	else
+		val = tda18271_thermometer[i].r0;
+
+	tda_map("(%d) tm = %d\n", i, val);
+
+	return val;
+}
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_cid_target_map {
+	u32 rfmax;
+	u8  target;
+	u16 limit;
+};
+
+static struct tda18271_cid_target_map tda18271_cid_target[] = {
+	{ .rfmax =  46000, .target = 0x04, .limit =  1800 },
+	{ .rfmax =  52200, .target = 0x0a, .limit =  1500 },
+	{ .rfmax =  79100, .target = 0x01, .limit =  4000 },
+	{ .rfmax = 136800, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 186250, .target = 0x0a, .limit =  4000 },
+	{ .rfmax = 230000, .target = 0x0a, .limit =  4000 },
+	{ .rfmax = 345000, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 426000, .target = 0x0e, .limit =  4000 },
+	{ .rfmax = 489500, .target = 0x1e, .limit =  4000 },
+	{ .rfmax = 697500, .target = 0x32, .limit =  4000 },
+	{ .rfmax = 842000, .target = 0x3a, .limit =  4000 },
+	{ .rfmax =      0, .target = 0x00, .limit =     0 }, /* end */
+};
+
+int tda18271_lookup_cid_target(struct dvb_frontend *fe,
+			       u32 *freq, u8 *cid_target, u16 *count_limit)
+{
+	int i = 0;
+
+	while ((tda18271_cid_target[i].rfmax * 1000) < *freq) {
+		if (tda18271_cid_target[i + 1].rfmax == 0)
+			break;
+		i++;
+	}
+	*cid_target  = tda18271_cid_target[i].target;
+	*count_limit = tda18271_cid_target[i].limit;
+
+	tda_map("(%d) cid_target = %02x, count_limit = %d\n", i,
+		tda18271_cid_target[i].target, tda18271_cid_target[i].limit);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = {
+	{ .rfmax =  47900, .rfband = 0x00,
+	  .rf1_def =  46000, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax =  61100, .rfband = 0x01,
+	  .rf1_def =  52200, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax = 152600, .rfband = 0x02,
+	  .rf1_def =  70100, .rf2_def = 136800, .rf3_def =      0 },
+	{ .rfmax = 164700, .rfband = 0x03,
+	  .rf1_def = 156700, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax = 203500, .rfband = 0x04,
+	  .rf1_def = 186250, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax = 457800, .rfband = 0x05,
+	  .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 },
+	{ .rfmax = 865000, .rfband = 0x06,
+	  .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 },
+	{ .rfmax =      0, .rfband = 0x00,
+	  .rf1_def =      0, .rf2_def =      0, .rf3_def =      0 }, /* end */
+};
+
+int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+	int i = 0;
+
+	while ((map[i].rfmax * 1000) < *freq) {
+		if (tda18271_debug & DBG_ADV)
+			tda_map("(%d) rfmax = %d < freq = %d, "
+				"rf1_def = %d, rf2_def = %d, rf3_def = %d, "
+				"rf1 = %d, rf2 = %d, rf3 = %d, "
+				"rf_a1 = %d, rf_a2 = %d, "
+				"rf_b1 = %d, rf_b2 = %d\n",
+				i, map[i].rfmax * 1000, *freq,
+				map[i].rf1_def, map[i].rf2_def, map[i].rf3_def,
+				map[i].rf1, map[i].rf2, map[i].rf3,
+				map[i].rf_a1, map[i].rf_a2,
+				map[i].rf_b1, map[i].rf_b2);
+		if (map[i].rfmax == 0)
+			return -EINVAL;
+		i++;
+	}
+	if (rf_band)
+		*rf_band = map[i].rfband;
+
+	tda_map("(%d) rf_band = %02x\n", i, map[i].rfband);
+
+	return i;
+}
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_map_layout {
+	struct tda18271_pll_map *main_pll;
+	struct tda18271_pll_map *cal_pll;
+
+	struct tda18271_map *rf_cal;
+	struct tda18271_map *rf_cal_kmco;
+	struct tda18271_map *rf_cal_dc_over_dt;
+
+	struct tda18271_map *bp_filter;
+	struct tda18271_map *rf_band;
+	struct tda18271_map *gain_taper;
+	struct tda18271_map *ir_measure;
+};
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_lookup_pll_map(struct dvb_frontend *fe,
+			    enum tda18271_map_type map_type,
+			    u32 *freq, u8 *post_div, u8 *div)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_pll_map *map = NULL;
+	unsigned int i = 0;
+	char *map_name;
+	int ret = 0;
+
+	BUG_ON(!priv->maps);
+
+	switch (map_type) {
+	case MAIN_PLL:
+		map = priv->maps->main_pll;
+		map_name = "main_pll";
+		break;
+	case CAL_PLL:
+		map = priv->maps->cal_pll;
+		map_name = "cal_pll";
+		break;
+	default:
+		/* we should never get here */
+		map_name = "undefined";
+		break;
+	}
+
+	if (!map) {
+		tda_warn("%s map is not set!\n", map_name);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	while ((map[i].lomax * 1000) < *freq) {
+		if (map[i + 1].lomax == 0) {
+			tda_map("%s: frequency (%d) out of range\n",
+				map_name, *freq);
+			ret = -ERANGE;
+			break;
+		}
+		i++;
+	}
+	*post_div = map[i].pd;
+	*div      = map[i].d;
+
+	tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n",
+		i, map_name, *post_div, *div);
+fail:
+	return ret;
+}
+
+int tda18271_lookup_map(struct dvb_frontend *fe,
+			enum tda18271_map_type map_type,
+			u32 *freq, u8 *val)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_map *map = NULL;
+	unsigned int i = 0;
+	char *map_name;
+	int ret = 0;
+
+	BUG_ON(!priv->maps);
+
+	switch (map_type) {
+	case BP_FILTER:
+		map = priv->maps->bp_filter;
+		map_name = "bp_filter";
+		break;
+	case RF_CAL_KMCO:
+		map = priv->maps->rf_cal_kmco;
+		map_name = "km";
+		break;
+	case RF_BAND:
+		map = priv->maps->rf_band;
+		map_name = "rf_band";
+		break;
+	case GAIN_TAPER:
+		map = priv->maps->gain_taper;
+		map_name = "gain_taper";
+		break;
+	case RF_CAL:
+		map = priv->maps->rf_cal;
+		map_name = "rf_cal";
+		break;
+	case IR_MEASURE:
+		map = priv->maps->ir_measure;
+		map_name = "ir_measure";
+		break;
+	case RF_CAL_DC_OVER_DT:
+		map = priv->maps->rf_cal_dc_over_dt;
+		map_name = "rf_cal_dc_over_dt";
+		break;
+	default:
+		/* we should never get here */
+		map_name = "undefined";
+		break;
+	}
+
+	if (!map) {
+		tda_warn("%s map is not set!\n", map_name);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	while ((map[i].rfmax * 1000) < *freq) {
+		if (map[i + 1].rfmax == 0) {
+			tda_map("%s: frequency (%d) out of range\n",
+				map_name, *freq);
+			ret = -ERANGE;
+			break;
+		}
+		i++;
+	}
+	*val = map[i].val;
+
+	tda_map("(%d) %s: 0x%02x\n", i, map_name, *val);
+fail:
+	return ret;
+}
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_std_map tda18271c1_std_map = {
+	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
+	.atv_b    = { .if_freq = 6750, .std_bits = 0x0e },
+	.atv_dk   = { .if_freq = 7750, .std_bits = 0x0f },
+	.atv_gh   = { .if_freq = 7750, .std_bits = 0x0f },
+	.atv_i    = { .if_freq = 7750, .std_bits = 0x0f },
+	.atv_l    = { .if_freq = 7750, .std_bits = 0x0f },
+	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0f },
+	.atv_mn   = { .if_freq = 5750, .std_bits = 0x0d },
+	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
+	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
+	.dvbt_7   = { .if_freq = 3800, .std_bits = 0x1d },
+	.dvbt_8   = { .if_freq = 4300, .std_bits = 0x1e },
+	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
+	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
+};
+
+static struct tda18271_std_map tda18271c2_std_map = {
+	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
+	.atv_b    = { .if_freq = 6000, .std_bits = 0x0d },
+	.atv_dk   = { .if_freq = 6900, .std_bits = 0x0e },
+	.atv_gh   = { .if_freq = 7100, .std_bits = 0x0e },
+	.atv_i    = { .if_freq = 7250, .std_bits = 0x0e },
+	.atv_l    = { .if_freq = 6900, .std_bits = 0x0e },
+	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0e },
+	.atv_mn   = { .if_freq = 5400, .std_bits = 0x0c },
+	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
+	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
+	.dvbt_7   = { .if_freq = 3500, .std_bits = 0x1c },
+	.dvbt_8   = { .if_freq = 4000, .std_bits = 0x1d },
+	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
+	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
+};
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_map_layout tda18271c1_map_layout = {
+	.main_pll          = tda18271c1_main_pll,
+	.cal_pll           = tda18271c1_cal_pll,
+
+	.rf_cal            = tda18271c1_rf_cal,
+	.rf_cal_kmco       = tda18271c1_km,
+
+	.bp_filter         = tda18271_bp_filter,
+	.rf_band           = tda18271_rf_band,
+	.gain_taper        = tda18271_gain_taper,
+	.ir_measure        = tda18271_ir_measure,
+};
+
+static struct tda18271_map_layout tda18271c2_map_layout = {
+	.main_pll          = tda18271c2_main_pll,
+	.cal_pll           = tda18271c2_cal_pll,
+
+	.rf_cal            = tda18271c2_rf_cal,
+	.rf_cal_kmco       = tda18271c2_km,
+
+	.rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt,
+
+	.bp_filter         = tda18271_bp_filter,
+	.rf_band           = tda18271_rf_band,
+	.gain_taper        = tda18271_gain_taper,
+	.ir_measure        = tda18271_ir_measure,
+};
+
+int tda18271_assign_map_layout(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret = 0;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		priv->maps = &tda18271c1_map_layout;
+		memcpy(&priv->std, &tda18271c1_std_map,
+		       sizeof(struct tda18271_std_map));
+		break;
+	case TDA18271HDC2:
+		priv->maps = &tda18271c2_map_layout;
+		memcpy(&priv->std, &tda18271c2_std_map,
+		       sizeof(struct tda18271_std_map));
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	memcpy(priv->rf_cal_state, &tda18271_rf_band_template,
+	       sizeof(tda18271_rf_band_template));
+
+	return ret;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */

+ 78 - 0
drivers/media/dvb/frontends/tda18271.h

@@ -0,0 +1,78 @@
+/*
+    tda18271.h - header for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; 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 __TDA18271_H__
+#define __TDA18271_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda18271_std_map_item {
+	u16 if_freq;
+	u8 std_bits;
+};
+
+struct tda18271_std_map {
+	struct tda18271_std_map_item fm_radio;
+	struct tda18271_std_map_item atv_b;
+	struct tda18271_std_map_item atv_dk;
+	struct tda18271_std_map_item atv_gh;
+	struct tda18271_std_map_item atv_i;
+	struct tda18271_std_map_item atv_l;
+	struct tda18271_std_map_item atv_lc;
+	struct tda18271_std_map_item atv_mn;
+	struct tda18271_std_map_item atsc_6;
+	struct tda18271_std_map_item dvbt_6;
+	struct tda18271_std_map_item dvbt_7;
+	struct tda18271_std_map_item dvbt_8;
+	struct tda18271_std_map_item qam_6;
+	struct tda18271_std_map_item qam_8;
+};
+
+enum tda18271_i2c_gate {
+	TDA18271_GATE_AUTO = 0,
+	TDA18271_GATE_ANALOG,
+	TDA18271_GATE_DIGITAL,
+};
+
+struct tda18271_config {
+	/* override default if freq / std settings (optional) */
+	struct tda18271_std_map *std_map;
+
+	/* use i2c gate provided by analog or digital demod */
+	enum tda18271_i2c_gate gate;
+};
+
+#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
+					    struct i2c_adapter *i2c,
+					    struct tda18271_config *cfg);
+#else
+static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe,
+						   u8 addr,
+						   struct i2c_adapter *i2c,
+						   struct tda18271_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* __TDA18271_H__ */

+ 352 - 15
drivers/media/dvb/frontends/tda827x.c

@@ -19,12 +19,16 @@
  */
 
 #include <linux/module.h>
-#include <linux/dvb/frontend.h>
 #include <asm/types.h>
+#include <linux/dvb/frontend.h>
+#include <linux/videodev2.h>
 
 #include "tda827x.h"
 
 static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
 #define dprintk(args...) \
 	do {					    \
 		if (debug) printk(KERN_DEBUG "tda827x: " args); \
@@ -34,10 +38,57 @@ struct tda827x_priv {
 	int i2c_addr;
 	struct i2c_adapter *i2c_adap;
 	struct tda827x_config *cfg;
+
+	unsigned int sgIF;
+	unsigned char lpsel;
+
 	u32 frequency;
 	u32 bandwidth;
 };
 
+static void tda827x_set_std(struct dvb_frontend *fe,
+			    struct analog_parameters *params)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	char *mode;
+
+	priv->lpsel = 0;
+	if (params->std & V4L2_STD_MN) {
+		priv->sgIF = 92;
+		priv->lpsel = 1;
+		mode = "MN";
+	} else if (params->std & V4L2_STD_B) {
+		priv->sgIF = 108;
+		mode = "B";
+	} else if (params->std & V4L2_STD_GH) {
+		priv->sgIF = 124;
+		mode = "GH";
+	} else if (params->std & V4L2_STD_PAL_I) {
+		priv->sgIF = 124;
+		mode = "I";
+	} else if (params->std & V4L2_STD_DK) {
+		priv->sgIF = 124;
+		mode = "DK";
+	} else if (params->std & V4L2_STD_SECAM_L) {
+		priv->sgIF = 124;
+		mode = "L";
+	} else if (params->std & V4L2_STD_SECAM_LC) {
+		priv->sgIF = 20;
+		mode = "LC";
+	} else {
+		priv->sgIF = 124;
+		mode = "xx";
+	}
+
+	if (params->mode == V4L2_TUNER_RADIO)
+		priv->sgIF = 88; /* if frequency is 5.5 MHz */
+
+	dprintk("setting tda827x to system %s\n", mode);
+}
+
+
+/* ------------------------------------------------------------------ */
+
 struct tda827x_data {
 	u32 lomax;
 	u8  spd;
@@ -48,7 +99,7 @@ struct tda827x_data {
 	u8 div1p5;
 };
 
-static const struct tda827x_data tda827x_dvbt[] = {
+static const struct tda827x_data tda827x_table[] = {
 	{ .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
 	{ .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
 	{ .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
@@ -106,21 +157,22 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
 	tuner_freq = params->frequency + if_freq;
 
 	i = 0;
-	while (tda827x_dvbt[i].lomax < tuner_freq) {
-		if(tda827x_dvbt[i + 1].lomax == 0)
+	while (tda827x_table[i].lomax < tuner_freq) {
+		if (tda827x_table[i + 1].lomax == 0)
 			break;
 		i++;
 	}
 
-	N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
+	N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
 	buf[0] = 0;
 	buf[1] = (N>>8) | 0x40;
 	buf[2] = N & 0xff;
 	buf[3] = 0;
 	buf[4] = 0x52;
-	buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
-				(tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
-	buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
+	buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +
+				(tda827x_table[i].bs << 3) +
+				tda827x_table[i].bp;
+	buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;
 	buf[7] = 0xbf;
 	buf[8] = 0x2a;
 	buf[9] = 0x05;
@@ -140,7 +192,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
 	msleep(500);
 	/* correct CP value */
 	buf[0] = 0x30;
-	buf[1] = 0x50 + tda827x_dvbt[i].cp;
+	buf[1] = 0x50 + tda827x_table[i].cp;
 	msg.len = 2;
 
 	if (fe->ops.i2c_gate_ctrl)
@@ -173,6 +225,102 @@ static int tda827xo_sleep(struct dvb_frontend *fe)
 
 /* ------------------------------------------------------------------ */
 
+static int tda827xo_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
+{
+	unsigned char tuner_reg[8];
+	unsigned char reg2[2];
+	u32 N;
+	int i;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };
+	unsigned int freq = params->frequency;
+
+	tda827x_set_std(fe, params);
+
+	if (params->mode == V4L2_TUNER_RADIO)
+		freq = freq / 1000;
+
+	N = freq + priv->sgIF;
+
+	i = 0;
+	while (tda827x_table[i].lomax < N * 62500) {
+		if (tda827x_table[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = N << tda827x_table[i].spd;
+
+	tuner_reg[0] = 0;
+	tuner_reg[1] = (unsigned char)(N>>8);
+	tuner_reg[2] = (unsigned char) N;
+	tuner_reg[3] = 0x40;
+	tuner_reg[4] = 0x52 + (priv->lpsel << 5);
+	tuner_reg[5] = (tda827x_table[i].spd    << 6) +
+		       (tda827x_table[i].div1p5 << 5) +
+		       (tda827x_table[i].bs     << 3) + tda827x_table[i].bp;
+	tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);
+	tuner_reg[7] = 0x8f;
+
+	msg.buf = tuner_reg;
+	msg.len = 8;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msg.buf = reg2;
+	msg.len = 2;
+	reg2[0] = 0x80;
+	reg2[1] = 0;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	reg2[0] = 0x60;
+	reg2[1] = 0xbf;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4] + 0x80;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(1);
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4] + 4;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(1);
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4];
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(550);
+	reg2[0] = 0x30;
+	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	reg2[0] = 0x60;
+	reg2[1] = 0x3f;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	reg2[0] = 0x80;
+	reg2[1] = 0x08;   /* Vsync en */
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	priv->frequency = freq * 62500;
+
+	return 0;
+}
+
+static void tda827xo_agcf(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char data[] = { 0x80, 0x0c };
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = data, .len = 2};
+
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+}
+
+/* ------------------------------------------------------------------ */
+
 struct tda827xa_data {
 	u32 lomax;
 	u8  svco;
@@ -212,6 +360,35 @@ static const struct tda827xa_data tda827xa_dvbt[] = {
 	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
 };
 
+static struct tda827xa_data tda827xa_analog[] = {
+	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},
+	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},
+	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
+	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
+	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+	{ .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+};
+
 static int tda827xa_set_params(struct dvb_frontend *fe,
 			       struct dvb_frontend_parameters *params)
 {
@@ -368,6 +545,163 @@ static int tda827xa_sleep(struct dvb_frontend *fe)
 	return 0;
 }
 
+/* ------------------------------------------------------------------ */
+
+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+			      struct analog_parameters *params)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char buf[] = {0x22, 0x01};
+	int arg;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	if (NULL == priv->cfg) {
+		dprintk("tda827x_config not defined, cannot set LNA gain!\n");
+		return;
+	}
+
+	if (priv->cfg->config) {
+		if (high)
+			dprintk("setting LNA to high gain\n");
+		else
+			dprintk("setting LNA to low gain\n");
+	}
+	switch (*priv->cfg->config) {
+	case 0: /* no LNA */
+		break;
+	case 1: /* switch is GPIO 0 of tda8290 */
+	case 2:
+		/* turn Vsync on */
+		if (params->std & V4L2_STD_MN)
+			arg = 1;
+		else
+			arg = 0;
+		if (priv->cfg->tuner_callback)
+			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
+						  1, arg);
+		buf[1] = high ? 0 : 1;
+		if (*priv->cfg->config == 2)
+			buf[1] = high ? 1 : 0;
+		i2c_transfer(priv->i2c_adap, &msg, 1);
+		break;
+	case 3: /* switch with GPIO of saa713x */
+		if (priv->cfg->tuner_callback)
+			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
+						  0, high);
+		break;
+	}
+}
+
+static int tda827xa_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
+{
+	unsigned char tuner_reg[11];
+	u32 N;
+	int i;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = tuner_reg, .len = sizeof(tuner_reg) };
+	unsigned int freq = params->frequency;
+
+	tda827x_set_std(fe, params);
+
+	tda827xa_lna_gain(fe, 1, params);
+	msleep(10);
+
+	if (params->mode == V4L2_TUNER_RADIO)
+		freq = freq / 1000;
+
+	N = freq + priv->sgIF;
+
+	i = 0;
+	while (tda827xa_analog[i].lomax < N * 62500) {
+		if (tda827xa_analog[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = N << tda827xa_analog[i].spd;
+
+	tuner_reg[0] = 0;
+	tuner_reg[1] = (unsigned char)(N>>8);
+	tuner_reg[2] = (unsigned char) N;
+	tuner_reg[3] = 0;
+	tuner_reg[4] = 0x16;
+	tuner_reg[5] = (tda827xa_analog[i].spd << 5) +
+		       (tda827xa_analog[i].svco << 3) +
+			tda827xa_analog[i].sbs;
+	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
+	tuner_reg[7] = 0x1c;
+	tuner_reg[8] = 4;
+	tuner_reg[9] = 0x20;
+	tuner_reg[10] = 0x00;
+	msg.len = 11;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0x90;
+	tuner_reg[1] = 0xff;
+	tuner_reg[2] = 0xe0;
+	tuner_reg[3] = 0;
+	tuner_reg[4] = 0x99 + (priv->lpsel << 1);
+	msg.len = 5;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0xa0;
+	tuner_reg[1] = 0xc0;
+	msg.len = 2;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0x30;
+	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msg.flags = I2C_M_RD;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+	msg.flags = 0;
+	tuner_reg[1] >>= 4;
+	dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
+	if (tuner_reg[1] < 1)
+		tda827xa_lna_gain(fe, 0, params);
+
+	msleep(100);
+	tuner_reg[0] = 0x60;
+	tuner_reg[1] = 0x3c;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(163);
+	tuner_reg[0] = 0x50;
+	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0x80;
+	tuner_reg[1] = 0x28;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0xb0;
+	tuner_reg[1] = 0x01;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0xc0;
+	tuner_reg[1] = 0x19 + (priv->lpsel << 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	priv->frequency = freq * 62500;
+
+	return 0;
+}
+
+static void tda827xa_agcf(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char data[] = {0x80, 0x2c};
+	struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
+			      .buf = data, .len = 2};
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+}
+
+/* ------------------------------------------------------------------ */
+
 static int tda827x_release(struct dvb_frontend *fe)
 {
 	kfree(fe->tuner_priv);
@@ -430,6 +764,7 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = {
 	.init = tda827x_initial_init,
 	.sleep = tda827x_initial_sleep,
 	.set_params = tda827xo_set_params,
+	.set_analog_params = tda827xo_set_analog_params,
 	.get_frequency = tda827x_get_frequency,
 	.get_bandwidth = tda827x_get_bandwidth,
 };
@@ -445,6 +780,7 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = {
 	.init = tda827x_init,
 	.sleep = tda827xa_sleep,
 	.set_params = tda827xa_set_params,
+	.set_analog_params = tda827xa_set_analog_params,
 	.get_frequency = tda827x_get_frequency,
 	.get_bandwidth = tda827x_get_bandwidth,
 };
@@ -465,9 +801,13 @@ static int tda827x_probe_version(struct dvb_frontend *fe)
 		dprintk("tda827x tuner found\n");
 		fe->ops.tuner_ops.init  = tda827x_init;
 		fe->ops.tuner_ops.sleep = tda827xo_sleep;
+		if (priv->cfg)
+			priv->cfg->agcf = tda827xo_agcf;
 	} else {
 		dprintk("tda827xa tuner found\n");
 		memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
+		if (priv->cfg)
+			priv->cfg->agcf = tda827xa_agcf;
 	}
 	return 0;
 }
@@ -487,16 +827,13 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
 	priv->i2c_adap = i2c;
 	priv->cfg = cfg;
 	memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
-
 	fe->tuner_priv = priv;
 
+	dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);
+
 	return fe;
 }
-
-EXPORT_SYMBOL(tda827x_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+EXPORT_SYMBOL_GPL(tda827x_attach);
 
 MODULE_DESCRIPTION("DVB TDA827x driver");
 MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");

+ 7 - 0
drivers/media/dvb/frontends/tda827x.h

@@ -29,9 +29,16 @@
 
 struct tda827x_config
 {
+	/* saa7134 - provided callbacks */
 	void (*lna_gain) (struct dvb_frontend *fe, int high);
 	int (*init) (struct dvb_frontend *fe);
 	int (*sleep) (struct dvb_frontend *fe);
+
+	/* interface to tda829x driver */
+	unsigned int *config;
+	int (*tuner_callback) (void *dev, int command, int arg);
+
+	void (*agcf)(struct dvb_frontend *fe);
 };
 
 

+ 2 - 2
drivers/media/dvb/frontends/ves1820.c

@@ -65,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
 	ret = i2c_transfer(state->i2c, &msg, 1);
 
 	if (ret != 1)
-		printk("ves1820: %s(): writereg error (reg == 0x%02x,"
+		printk("ves1820: %s(): writereg error (reg == 0x%02x, "
 			"val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
 
 	return (ret != 1) ? -EREMOTEIO : 0;
@@ -84,7 +84,7 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
 	ret = i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2)
-		printk("ves1820: %s(): readreg error (reg == 0x%02x,"
+		printk("ves1820: %s(): readreg error (reg == 0x%02x, "
 		"ret == %i)\n", __FUNCTION__, reg, ret);
 
 	return b1[0];

+ 964 - 0
drivers/media/dvb/frontends/xc5000.c

@@ -0,0 +1,964 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Xceive Corporation
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "xc5000.h"
+#include "xc5000_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
+
+#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
+#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+
+/* Misc Defines */
+#define MAX_TV_STANDARD			23
+#define XC_MAX_I2C_WRITE_LENGTH		64
+
+/* Signal Types */
+#define XC_RF_MODE_AIR			0
+#define XC_RF_MODE_CABLE		1
+
+/* Result codes */
+#define XC_RESULT_SUCCESS		0
+#define XC_RESULT_RESET_FAILURE		1
+#define XC_RESULT_I2C_WRITE_FAILURE	2
+#define XC_RESULT_I2C_READ_FAILURE	3
+#define XC_RESULT_OUT_OF_RANGE		5
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
+#define XC_PRODUCT_ID_FW_LOADED 	0x1388
+
+/* Registers */
+#define XREG_INIT         0x00
+#define XREG_VIDEO_MODE   0x01
+#define XREG_AUDIO_MODE   0x02
+#define XREG_RF_FREQ      0x03
+#define XREG_D_CODE       0x04
+#define XREG_IF_OUT       0x05
+#define XREG_SEEK_MODE    0x07
+#define XREG_POWER_DOWN   0x0A
+#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_XTALFREQ     0x0F
+#define XREG_FINERFFREQ   0x10
+#define XREG_DDIMODE      0x11
+
+#define XREG_ADC_ENV      0x00
+#define XREG_QUALITY      0x01
+#define XREG_FRAME_LINES  0x02
+#define XREG_HSYNC_FREQ   0x03
+#define XREG_LOCK         0x04
+#define XREG_FREQ_ERROR   0x05
+#define XREG_SNR          0x06
+#define XREG_VERSION      0x07
+#define XREG_PRODUCT_ID   0x08
+#define XREG_BUSY         0x09
+
+/*
+   Basic firmware description. This will remain with
+   the driver for documentation purposes.
+
+   This represents an I2C firmware file encoded as a
+   string of unsigned char. Format is as follows:
+
+   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
+   char[1  ]=len0_LSB  -> length of first write transaction
+   char[2  ]=data0 -> first byte to be sent
+   char[3  ]=data1
+   char[4  ]=data2
+   char[   ]=...
+   char[M  ]=dataN  -> last byte to be sent
+   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
+   char[M+2]=len1_LSB  -> length of second write transaction
+   char[M+3]=data0
+   char[M+4]=data1
+   ...
+   etc.
+
+   The [len] value should be interpreted as follows:
+
+   len= len_MSB _ len_LSB
+   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
+   len=0000_0000_0000_0000   : Reset command: Do hardware reset
+   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
+   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
+
+   For the RESET and WAIT commands, the two following bytes will contain
+   immediately the length of the following transaction.
+
+*/
+typedef struct {
+	char *Name;
+	u16 AudioMode;
+	u16 VideoMode;
+} XC_TV_STANDARD;
+
+/* Tuner standards */
+#define MN_NTSC_PAL_BTSC	0
+#define MN_NTSC_PAL_A2		1
+#define MN_NTSC_PAL_EIAJ	2
+#define MN_NTSC_PAL_Mono	3
+#define BG_PAL_A2		4
+#define BG_PAL_NICAM		5
+#define BG_PAL_MONO		6
+#define I_PAL_NICAM		7
+#define I_PAL_NICAM_MONO	8
+#define DK_PAL_A2		9
+#define DK_PAL_NICAM		10
+#define DK_PAL_MONO		11
+#define DK_SECAM_A2DK1		12
+#define DK_SECAM_A2LDK3 	13
+#define DK_SECAM_A2MONO 	14
+#define L_SECAM_NICAM		15
+#define LC_SECAM_NICAM		16
+#define DTV6			17
+#define DTV8			18
+#define DTV7_8			19
+#define DTV7			20
+#define FM_Radio_INPUT2 	21
+#define FM_Radio_INPUT1 	22
+
+XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+	{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
+	{"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
+	{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
+	{"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
+	{"B/G-PAL-A2",        0x0A00, 0x8049},
+	{"B/G-PAL-NICAM",     0x0C04, 0x8049},
+	{"B/G-PAL-MONO",      0x0878, 0x8059},
+	{"I-PAL-NICAM",       0x1080, 0x8009},
+	{"I-PAL-NICAM-MONO",  0x0E78, 0x8009},
+	{"D/K-PAL-A2",        0x1600, 0x8009},
+	{"D/K-PAL-NICAM",     0x0E80, 0x8009},
+	{"D/K-PAL-MONO",      0x1478, 0x8009},
+	{"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
+	{"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009},
+	{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
+	{"L-SECAM-NICAM",     0x8E82, 0x0009},
+	{"L'-SECAM-NICAM",    0x8E82, 0x4009},
+	{"DTV6",              0x00C0, 0x8002},
+	{"DTV8",              0x00C0, 0x800B},
+	{"DTV7/8",            0x00C0, 0x801B},
+	{"DTV7",              0x00C0, 0x8007},
+	{"FM Radio-INPUT2",   0x9802, 0x9002},
+	{"FM Radio-INPUT1",   0x0208, 0x9002}
+};
+
+static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
+static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
+static void xc5000_TunerReset(struct dvb_frontend *fe);
+
+static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+	return xc5000_writeregs(priv, buf, len)
+		? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
+}
+
+static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+	return xc5000_readregs(priv, buf, len)
+		? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
+}
+
+static int xc_reset(struct dvb_frontend *fe)
+{
+	xc5000_TunerReset(fe);
+	return XC_RESULT_SUCCESS;
+}
+
+static void xc_wait(int wait_ms)
+{
+	msleep(wait_ms);
+}
+
+static void xc5000_TunerReset(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if (priv->cfg->tuner_callback) {
+		ret = priv->cfg->tuner_callback(priv->cfg->priv,
+						XC5000_TUNER_RESET, 0);
+		if (ret)
+			printk(KERN_ERR "xc5000: reset failed\n");
+	} else
+		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+}
+
+static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
+{
+	u8 buf[4];
+	int WatchDogTimer = 5;
+	int result;
+
+	buf[0] = (regAddr >> 8) & 0xFF;
+	buf[1] = regAddr & 0xFF;
+	buf[2] = (i2cData >> 8) & 0xFF;
+	buf[3] = i2cData & 0xFF;
+	result = xc_send_i2c_data(priv, buf, 4);
+	if (result == XC_RESULT_SUCCESS) {
+		/* wait for busy flag to clear */
+		while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
+			buf[0] = 0;
+			buf[1] = XREG_BUSY;
+
+			result = xc_send_i2c_data(priv, buf, 2);
+			if (result == XC_RESULT_SUCCESS) {
+				result = xc_read_i2c_data(priv, buf, 2);
+				if (result == XC_RESULT_SUCCESS) {
+					if ((buf[0] == 0) && (buf[1] == 0)) {
+						/* busy flag cleared */
+					break;
+					} else {
+						xc_wait(100); /* wait 5 ms */
+						WatchDogTimer--;
+					}
+				}
+			}
+		}
+	}
+	if (WatchDogTimer < 0)
+		result = XC_RESULT_I2C_WRITE_FAILURE;
+
+	return result;
+}
+
+static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
+{
+	u8 buf[2];
+	int result;
+
+	buf[0] = (regAddr >> 8) & 0xFF;
+	buf[1] = regAddr & 0xFF;
+	result = xc_send_i2c_data(priv, buf, 2);
+	if (result != XC_RESULT_SUCCESS)
+		return result;
+
+	result = xc_read_i2c_data(priv, buf, 2);
+	if (result != XC_RESULT_SUCCESS)
+		return result;
+
+	*i2cData = buf[0] * 256 + buf[1];
+	return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[])
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+
+	int i, nbytes_to_send, result;
+	unsigned int len, pos, index;
+	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+	index=0;
+	while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) {
+		len = i2c_sequence[index]* 256 + i2c_sequence[index+1];
+		if (len == 0x0000) {
+			/* RESET command */
+			result = xc_reset(fe);
+			index += 2;
+			if (result != XC_RESULT_SUCCESS)
+				return result;
+		} else if (len & 0x8000) {
+			/* WAIT command */
+			xc_wait(len & 0x7FFF);
+			index += 2;
+		} else {
+			/* Send i2c data whilst ensuring individual transactions
+			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+			 */
+			index += 2;
+			buf[0] = i2c_sequence[index];
+			buf[1] = i2c_sequence[index + 1];
+			pos = 2;
+			while (pos < len) {
+				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) {
+					nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH;
+				} else {
+					nbytes_to_send = (len - pos + 2);
+				}
+				for (i=2; i<nbytes_to_send; i++) {
+					buf[i] = i2c_sequence[index + pos + i - 2];
+				}
+				result = xc_send_i2c_data(priv, buf, nbytes_to_send);
+
+				if (result != XC_RESULT_SUCCESS)
+					return result;
+
+				pos += nbytes_to_send - 2;
+			}
+			index += len;
+		}
+	}
+	return XC_RESULT_SUCCESS;
+}
+
+static int xc_initialize(struct xc5000_priv *priv)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+	return xc_write_reg(priv, XREG_INIT, 0);
+}
+
+static int xc_SetTVStandard(struct xc5000_priv *priv,
+	u16 VideoMode, u16 AudioMode)
+{
+	int ret;
+	dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode);
+	dprintk(1, "%s() Standard = %s\n",
+		__FUNCTION__,
+		XC5000_Standard[priv->video_standard].Name);
+
+	ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
+	if (ret == XC_RESULT_SUCCESS)
+		ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
+
+	return ret;
+}
+
+static int xc_shutdown(struct xc5000_priv *priv)
+{
+	return 0;
+	/* Fixme: cannot bring tuner back alive once shutdown
+	 *        without reloading the driver modules.
+	 *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
+	 */
+}
+
+static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
+{
+	dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode,
+		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
+	{
+		rf_mode = XC_RF_MODE_CABLE;
+		printk(KERN_ERR
+			"%s(), Invalid mode, defaulting to CABLE",
+			__FUNCTION__);
+	}
+	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops;
+
+static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
+{
+	u16 freq_code;
+
+	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
+
+	if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
+		(freq_hz < xc5000_tuner_ops.info.frequency_min))
+		return XC_RESULT_OUT_OF_RANGE;
+
+	freq_code = (u16)(freq_hz / 15625);
+
+	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+}
+
+
+static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
+{
+	u32 freq_code = (freq_khz * 1024)/1000;
+	dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
+		__FUNCTION__, freq_khz, freq_code);
+
+	return xc_write_reg(priv, XREG_IF_OUT, freq_code);
+}
+
+
+static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
+{
+	return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
+{
+	int result;
+	u16 regData;
+	u32 tmp;
+
+	result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
+	if (result)
+		return result;
+
+	tmp = (u32)regData;
+	(*freq_error_hz) = (tmp * 15625) / 1000;
+	return result;
+}
+
+static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
+{
+	return xc_read_reg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc5000_priv *priv,
+	u8 *hw_majorversion, u8 *hw_minorversion,
+	u8 *fw_majorversion, u8 *fw_minorversion)
+{
+	u16 data;
+	int result;
+
+	result = xc_read_reg(priv, XREG_VERSION, &data);
+	if (result)
+		return result;
+
+	(*hw_majorversion) = (data >> 12) & 0x0F;
+	(*hw_minorversion) = (data >>  8) & 0x0F;
+	(*fw_majorversion) = (data >>  4) & 0x0F;
+	(*fw_minorversion) = data & 0x0F;
+
+	return 0;
+}
+
+static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
+{
+	u16 regData;
+	int result;
+
+	result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
+	if (result)
+		return result;
+
+	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+	return result;
+}
+
+static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
+{
+	return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
+{
+	return xc_read_reg(priv, XREG_QUALITY, quality);
+}
+
+static u16 WaitForLock(struct xc5000_priv *priv)
+{
+	u16 lockState = 0;
+	int watchDogCount = 40;
+
+	while ((lockState == 0) && (watchDogCount > 0)) {
+		xc_get_lock_status(priv, &lockState);
+		if (lockState != 1) {
+			xc_wait(5);
+			watchDogCount--;
+		}
+	}
+	return lockState;
+}
+
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
+{
+	int found = 0;
+
+	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
+
+	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
+		return 0;
+
+	if (WaitForLock(priv) == 1)
+		found = 1;
+
+	return found;
+}
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+	u8 buf[2] = { reg >> 8, reg & 0xff };
+	u8 bval[2] = { 0, 0 };
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address,
+			.flags = 0, .buf = &buf[0], .len = 2 },
+		{ .addr = priv->cfg->i2c_address,
+			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "xc5000: I2C read failed\n");
+		return -EREMOTEIO;
+	}
+
+	*val = (bval[0] << 8) | bval[1];
+	return 0;
+}
+
+static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
+{
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+		.flags = 0, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
+			(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
+{
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+		.flags = I2C_M_RD, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int xc5000_fwupload(struct dvb_frontend* fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	const struct firmware *fw;
+	int ret;
+
+	/* request the firmware, this will block and timeout */
+	printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
+		XC5000_DEFAULT_FIRMWARE);
+
+	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+	if (ret) {
+		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
+		ret = XC_RESULT_RESET_FAILURE;
+		goto out;
+	} else {
+		printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
+		       fw->size);
+		ret = XC_RESULT_SUCCESS;
+	}
+
+	if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) {
+		printk(KERN_ERR "xc5000: firmware incorrect size\n");
+		ret = XC_RESULT_RESET_FAILURE;
+	} else {
+		printk(KERN_INFO "xc5000: firmware upload\n");
+		ret = xc_load_i2c_sequence(fe,  fw->data );
+	}
+
+out:
+	release_firmware(fw);
+	return ret;
+}
+
+static void xc_debug_dump(struct xc5000_priv *priv)
+{
+	u16 adc_envelope;
+	u32 freq_error_hz = 0;
+	u16 lock_status;
+	u32 hsync_freq_hz = 0;
+	u16 frame_lines;
+	u16 quality;
+	u8 hw_majorversion = 0, hw_minorversion = 0;
+	u8 fw_majorversion = 0, fw_minorversion = 0;
+
+	/* Wait for stats to stabilize.
+	 * Frame Lines needs two frame times after initial lock
+	 * before it is valid.
+	 */
+	xc_wait(100);
+
+	xc_get_ADC_Envelope(priv,  &adc_envelope);
+	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+	xc_get_frequency_error(priv, &freq_error_hz);
+	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+	xc_get_lock_status(priv,  &lock_status);
+	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+		lock_status);
+
+	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
+		&fw_majorversion, &fw_minorversion);
+	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+		hw_majorversion, hw_minorversion,
+		fw_majorversion, fw_minorversion);
+
+	xc_get_hsync_freq(priv,  &hsync_freq_hz);
+	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
+
+	xc_get_frame_lines(priv,  &frame_lines);
+	dprintk(1, "*** Frame lines = %d\n", frame_lines);
+
+	xc_get_quality(priv,  &quality);
+	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+}
+
+static int xc5000_set_params(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency);
+
+	switch(params->u.vsb.modulation) {
+	case VSB_8:
+	case VSB_16:
+		dprintk(1, "%s() VSB modulation\n", __FUNCTION__);
+		priv->rf_mode = XC_RF_MODE_AIR;
+		priv->freq_hz = params->frequency - 1750000;
+		priv->bandwidth = BANDWIDTH_6_MHZ;
+		priv->video_standard = DTV6;
+		break;
+	case QAM_64:
+	case QAM_256:
+	case QAM_AUTO:
+		dprintk(1, "%s() QAM modulation\n", __FUNCTION__);
+		priv->rf_mode = XC_RF_MODE_CABLE;
+		priv->freq_hz = params->frequency - 1750000;
+		priv->bandwidth = BANDWIDTH_6_MHZ;
+		priv->video_standard = DTV6;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dprintk(1, "%s() frequency=%d (compensated)\n",
+		__FUNCTION__, priv->freq_hz);
+
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetTVStandard(priv,
+		XC5000_Standard[priv->video_standard].VideoMode,
+		XC5000_Standard[priv->video_standard].AudioMode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
+			priv->cfg->if_khz);
+		return -EIO;
+	}
+
+	xc_tune_channel(priv, priv->freq_hz);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
+
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+	struct analog_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	if(priv->fwloaded == 0)
+		xc_load_fw_and_init_tuner(fe);
+
+	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+		__FUNCTION__, params->frequency);
+
+	priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */
+
+	/* params->frequency is in units of 62.5khz */
+	priv->freq_hz = params->frequency * 62500;
+
+	/* FIX ME: Some video standards may have several possible audio
+		   standards. We simply default to one of them here.
+	 */
+	if(params->std & V4L2_STD_MN) {
+		/* default to BTSC audio standard */
+		priv->video_standard = MN_NTSC_PAL_BTSC;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_PAL_BG) {
+		/* default to NICAM audio standard */
+		priv->video_standard = BG_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_PAL_I) {
+		/* default to NICAM audio standard */
+		priv->video_standard = I_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_PAL_DK) {
+		/* default to NICAM audio standard */
+		priv->video_standard = DK_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_SECAM_DK) {
+		/* default to A2 DK1 audio standard */
+		priv->video_standard = DK_SECAM_A2DK1;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_SECAM_L) {
+		priv->video_standard = L_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_SECAM_LC) {
+		priv->video_standard = LC_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+tune_channel:
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+	printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetTVStandard(priv,
+		XC5000_Standard[priv->video_standard].VideoMode,
+		XC5000_Standard[priv->video_standard].AudioMode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	xc_tune_channel(priv, priv->freq_hz);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+	*freq = priv->freq_hz;
+	return 0;
+}
+
+static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	*bw = priv->bandwidth;
+	return 0;
+}
+
+static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	u16 lock_status = 0;
+
+	xc_get_lock_status(priv, &lock_status);
+
+	dprintk(1, "%s() lock_status = 0x%08x\n", __FUNCTION__, lock_status);
+
+	*status = lock_status;
+
+	return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret = 0;
+
+	if (priv->fwloaded == 0) {
+		ret = xc5000_fwupload(fe);
+		if (ret != XC_RESULT_SUCCESS)
+			return ret;
+		priv->fwloaded = 1;
+	}
+
+	/* Start the tuner self-calibration process */
+	ret |= xc_initialize(priv);
+
+	/* Wait for calibration to complete.
+	 * We could continue but XC5000 will clock stretch subsequent
+	 * I2C transactions until calibration is complete.  This way we
+	 * don't have to rely on clock stretching working.
+	 */
+	xc_wait( 100 );
+
+	/* Default to "CABLE" mode */
+	ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+
+	return ret;
+}
+
+static int xc5000_sleep(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	/* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
+	 * once shutdown without reloading the driver. Maybe I am not
+	 * doing something right.
+	 *
+	 */
+
+	ret = xc_shutdown(priv);
+	if(ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: %s() unable to shutdown tuner\n",
+			__FUNCTION__);
+		return -EREMOTEIO;
+	}
+	else {
+		/* priv->fwloaded = 0; */
+		return XC_RESULT_SUCCESS;
+	}
+}
+
+static int xc5000_init(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
+		return -EREMOTEIO;
+	}
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc5000_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops = {
+	.info = {
+		.name           = "Xceive XC5000",
+		.frequency_min  =    1000000,
+		.frequency_max  = 1023000000,
+		.frequency_step =      50000,
+	},
+
+	.release	   = xc5000_release,
+	.init		   = xc5000_init,
+	.sleep		   = xc5000_sleep,
+
+	.set_params	   = xc5000_set_params,
+	.set_analog_params = xc5000_set_analog_params,
+	.get_frequency	   = xc5000_get_frequency,
+	.get_bandwidth	   = xc5000_get_bandwidth,
+	.get_status	   = xc5000_get_status
+};
+
+struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c,
+	struct xc5000_config *cfg)
+{
+	struct xc5000_priv *priv = NULL;
+	u16 id = 0;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->bandwidth = BANDWIDTH_6_MHZ;
+	priv->i2c = i2c;
+
+	/* Check if firmware has been loaded. It is possible that another
+	   instance of the driver has loaded the firmware.
+	 */
+	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
+		kfree(priv);
+		return NULL;
+	}
+
+	switch(id) {
+	case XC_PRODUCT_ID_FW_LOADED:
+		printk(KERN_INFO
+			"xc5000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc5000: Firmware has been loaded previously\n");
+		priv->fwloaded = 1;
+		break;
+	case XC_PRODUCT_ID_FW_NOT_LOADED:
+		printk(KERN_INFO
+			"xc5000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc5000: Firmware has not been loaded previously\n");
+		priv->fwloaded = 0;
+		break;
+	default:
+		printk(KERN_ERR
+			"xc5000: Device not found at addr 0x%02x (0x%x)\n",
+			cfg->i2c_address, id);
+		kfree(priv);
+		return NULL;
+	}
+
+	memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	return fe;
+}
+EXPORT_SYMBOL(xc5000_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
+MODULE_LICENSE("GPL");

+ 62 - 0
drivers/media/dvb/frontends/xc5000.h

@@ -0,0 +1,62 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.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 __XC5000_H__
+#define __XC5000_H__
+
+#include <linux/firmware.h>
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct xc5000_config {
+	u8   i2c_address;
+	u32  if_khz;
+
+	/* For each bridge framework, when it attaches either analog or digital,
+	 * it has to store a reference back to its _core equivalent structure,
+	 * so that it can service the hardware by steering gpio's etc.
+	 * Each bridge implementation is different so cast priv accordingly.
+	 * The xc5000 driver cares not for this value, other than ensuring
+	 * it's passed back to a bridge during tuner_callback().
+	 */
+	void *priv;
+	int  (*tuner_callback) (void *priv, int command, int arg);
+};
+
+/* xc5000 callback command */
+#define XC5000_TUNER_RESET		0
+
+#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE)
+extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+					  struct i2c_adapter *i2c,
+					  struct xc5000_config *cfg);
+#else
+static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+						 struct i2c_adapter *i2c,
+						 struct xc5000_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TUNER_XC5000
+
+#endif // __XC5000_H__

+ 36 - 0
drivers/media/dvb/frontends/xc5000_priv.h

@@ -0,0 +1,36 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.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 XC5000_PRIV_H
+#define XC5000_PRIV_H
+
+struct xc5000_priv {
+	struct xc5000_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 freq_hz;
+	u32 bandwidth;
+	u8  video_standard;
+	u8  rf_mode;
+	u8  fwloaded;
+};
+
+#endif

+ 288 - 39
drivers/media/dvb/frontends/zl10353.c

@@ -1,7 +1,7 @@
 /*
  * Driver for Zarlink DVB-T ZL10353 demodulator
  *
- * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
  *
  * 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
@@ -16,7 +16,7 @@
  *
  * 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.=
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/kernel.h>
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <asm/div64.h>
 
 #include "dvb_frontend.h"
 #include "zl10353_priv.h"
@@ -35,6 +36,8 @@ struct zl10353_state {
 	struct dvb_frontend frontend;
 
 	struct zl10353_config config;
+
+	enum fe_bandwidth bandwidth;
 };
 
 static int debug;
@@ -122,9 +125,10 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
 				      enum fe_bandwidth bandwidth,
 				      u16 *nominal_rate)
 {
-	u32 adc_clock = 45056; /* 45.056 MHz */
-	u8 bw;
 	struct zl10353_state *state = fe->demodulator_priv;
+	u32 adc_clock = 450560; /* 45.056 MHz */
+	u64 value;
+	u8 bw;
 
 	if (state->config.adc_clock)
 		adc_clock = state->config.adc_clock;
@@ -142,12 +146,44 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
 		break;
 	}
 
-	*nominal_rate = (bw * (1 << 23) / 7 * 125 + adc_clock / 2) / adc_clock;
+	value = (u64)10 * (1 << 23) / 7 * 125;
+	value = (bw * value) + adc_clock / 2;
+	do_div(value, adc_clock);
+	*nominal_rate = value;
 
 	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
 		__FUNCTION__, bw, adc_clock, *nominal_rate);
 }
 
+static void zl10353_calc_input_freq(struct dvb_frontend *fe,
+				    u16 *input_freq)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u32 adc_clock = 450560;	/* 45.056  MHz */
+	int if2 = 361667;	/* 36.1667 MHz */
+	int ife;
+	u64 value;
+
+	if (state->config.adc_clock)
+		adc_clock = state->config.adc_clock;
+	if (state->config.if2)
+		if2 = state->config.if2;
+
+	if (adc_clock >= if2 * 2)
+		ife = if2;
+	else {
+		ife = adc_clock - (if2 % adc_clock);
+		if (ife > adc_clock / 2)
+			ife = adc_clock - ife;
+	}
+	value = (u64)65536 * ife + adc_clock / 2;
+	do_div(value, adc_clock);
+	*input_freq = -value;
+
+	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
+		__FUNCTION__, if2, ife, adc_clock, -(int)value, *input_freq);
+}
+
 static int zl10353_sleep(struct dvb_frontend *fe)
 {
 	static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
@@ -160,64 +196,276 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
 				  struct dvb_frontend_parameters *param)
 {
 	struct zl10353_state *state = fe->demodulator_priv;
-	u16 nominal_rate;
-	u8 pllbuf[6] = { 0x67 };
+	u16 nominal_rate, input_freq;
+	u8 pllbuf[6] = { 0x67 }, acq_ctl = 0;
+	u16 tps = 0;
+	struct dvb_ofdm_parameters *op = &param->u.ofdm;
 
-	/* These settings set "auto-everything" and start the FSM. */
-	zl10353_single_write(fe, 0x55, 0x80);
+	zl10353_single_write(fe, RESET, 0x80);
 	udelay(200);
 	zl10353_single_write(fe, 0xEA, 0x01);
 	udelay(200);
 	zl10353_single_write(fe, 0xEA, 0x00);
 
-	zl10353_single_write(fe, 0x56, 0x28);
-	zl10353_single_write(fe, 0x89, 0x20);
-	zl10353_single_write(fe, 0x5E, 0x00);
+	zl10353_single_write(fe, AGC_TARGET, 0x28);
+
+	if (op->transmission_mode != TRANSMISSION_MODE_AUTO)
+		acq_ctl |= (1 << 0);
+	if (op->guard_interval != GUARD_INTERVAL_AUTO)
+		acq_ctl |= (1 << 1);
+	zl10353_single_write(fe, ACQ_CTL, acq_ctl);
 
-	zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
+	switch (op->bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		/* These are extrapolated from the 7 and 8MHz values */
+		zl10353_single_write(fe, MCLK_RATIO, 0x97);
+		zl10353_single_write(fe, 0x64, 0x34);
+		break;
+	case BANDWIDTH_7_MHZ:
+		zl10353_single_write(fe, MCLK_RATIO, 0x86);
+		zl10353_single_write(fe, 0x64, 0x35);
+		break;
+	case BANDWIDTH_8_MHZ:
+	default:
+		zl10353_single_write(fe, MCLK_RATIO, 0x75);
+		zl10353_single_write(fe, 0x64, 0x36);
+	}
+
+	zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);
 	zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
 	zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
+	state->bandwidth = op->bandwidth;
+
+	zl10353_calc_input_freq(fe, &input_freq);
+	zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq));
+	zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq));
+
+	/* Hint at TPS settings */
+	switch (op->code_rate_HP) {
+	case FEC_2_3:
+		tps |= (1 << 7);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 7);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 7);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 7);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->code_rate_LP) {
+	case FEC_2_3:
+		tps |= (1 << 4);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 4);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 4);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 4);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+		break;
+	case FEC_NONE:
+		if (op->hierarchy_information == HIERARCHY_AUTO ||
+		    op->hierarchy_information == HIERARCHY_NONE)
+			break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->constellation) {
+	case QPSK:
+		break;
+	case QAM_AUTO:
+	case QAM_16:
+		tps |= (1 << 13);
+		break;
+	case QAM_64:
+		tps |= (2 << 13);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+	case TRANSMISSION_MODE_AUTO:
+		break;
+	case TRANSMISSION_MODE_8K:
+		tps |= (1 << 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->guard_interval) {
+	case GUARD_INTERVAL_1_32:
+	case GUARD_INTERVAL_AUTO:
+		break;
+	case GUARD_INTERVAL_1_16:
+		tps |= (1 << 2);
+		break;
+	case GUARD_INTERVAL_1_8:
+		tps |= (2 << 2);
+		break;
+	case GUARD_INTERVAL_1_4:
+		tps |= (3 << 2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->hierarchy_information) {
+	case HIERARCHY_AUTO:
+	case HIERARCHY_NONE:
+		break;
+	case HIERARCHY_1:
+		tps |= (1 << 10);
+		break;
+	case HIERARCHY_2:
+		tps |= (2 << 10);
+		break;
+	case HIERARCHY_4:
+		tps |= (3 << 10);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	zl10353_single_write(fe, TPS_GIVEN_1, msb(tps));
+	zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps));
 
-	zl10353_single_write(fe, 0x6C, 0xCD);
-	zl10353_single_write(fe, 0x6D, 0x7E);
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 0);
 
-	// if there is no attached secondary tuner, we call set_params to program
-	// a potential tuner attached somewhere else
+	/*
+	 * If there is no tuner attached to the secondary I2C bus, we call
+	 * set_params to program a potential tuner attached somewhere else.
+	 * Otherwise, we update the PLL registers via calc_regs.
+	 */
 	if (state->config.no_tuner) {
 		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);
 		}
+	} else if (fe->ops.tuner_ops.calc_regs) {
+		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5);
+		pllbuf[1] <<= 1;
+		zl10353_write(fe, pllbuf, sizeof(pllbuf));
 	}
 
-	// if pllbuf is defined, retrieve the settings
-	if (fe->ops.tuner_ops.calc_regs) {
-		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
-		pllbuf[1] <<= 1;
-	} else {
-		// fake pllbuf settings
-		pllbuf[1] = 0x61 << 1;
-		pllbuf[2] = 0;
-		pllbuf[3] = 0;
-		pllbuf[3] = 0;
-		pllbuf[4] = 0;
+	zl10353_single_write(fe, 0x5F, 0x13);
+
+	/* If no attached tuner or invalid PLL registers, just start the FSM. */
+	if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL)
+		zl10353_single_write(fe, FSM_GO, 0x01);
+	else
+		zl10353_single_write(fe, TUNER_GO, 0x01);
+
+	return 0;
+}
+
+static int zl10353_get_parameters(struct dvb_frontend *fe,
+				  struct dvb_frontend_parameters *param)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	struct dvb_ofdm_parameters *op = &param->u.ofdm;
+	int s6, s9;
+	u16 tps;
+	static const u8 tps_fec_to_api[8] = {
+		FEC_1_2,
+		FEC_2_3,
+		FEC_3_4,
+		FEC_5_6,
+		FEC_7_8,
+		FEC_AUTO,
+		FEC_AUTO,
+		FEC_AUTO
+	};
+
+	s6 = zl10353_read_register(state, STATUS_6);
+	s9 = zl10353_read_register(state, STATUS_9);
+	if (s6 < 0 || s9 < 0)
+		return -EREMOTEIO;
+	if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0)
+		return -EINVAL;	/* no FE or TPS lock */
+
+	tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 |
+	      zl10353_read_register(state, TPS_RECEIVED_0);
+
+	op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
+	op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
+
+	switch ((tps >> 13) & 3) {
+	case 0:
+		op->constellation = QPSK;
+		break;
+	case 1:
+		op->constellation = QAM_16;
+		break;
+	case 2:
+		op->constellation = QAM_64;
+		break;
+	default:
+		op->constellation = QAM_AUTO;
+		break;
 	}
 
-	// there is no call to _just_ start decoding, so we send the pllbuf anyway
-	// even if there isn't a PLL attached to the secondary bus
-	zl10353_write(fe, pllbuf, sizeof(pllbuf));
+	op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
+					       TRANSMISSION_MODE_2K;
 
-	zl10353_single_write(fe, 0x5F, 0x13);
-	zl10353_single_write(fe, 0x70, 0x01);
-	udelay(250);
-	zl10353_single_write(fe, 0xE4, 0x00);
-	zl10353_single_write(fe, 0xE5, 0x2A);
-	zl10353_single_write(fe, 0xE9, 0x02);
-	zl10353_single_write(fe, 0xE7, 0x40);
-	zl10353_single_write(fe, 0xE8, 0x10);
+	switch ((tps >> 2) & 3) {
+	case 0:
+		op->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		op->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		op->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		op->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	default:
+		op->guard_interval = GUARD_INTERVAL_AUTO;
+		break;
+	}
+
+	switch ((tps >> 10) & 7) {
+	case 0:
+		op->hierarchy_information = HIERARCHY_NONE;
+		break;
+	case 1:
+		op->hierarchy_information = HIERARCHY_1;
+		break;
+	case 2:
+		op->hierarchy_information = HIERARCHY_2;
+		break;
+	case 3:
+		op->hierarchy_information = HIERARCHY_4;
+		break;
+	default:
+		op->hierarchy_information = HIERARCHY_AUTO;
+		break;
+	}
+
+	param->frequency = 0;
+	op->bandwidth = state->bandwidth;
+	param->inversion = INVERSION_AUTO;
 
 	return 0;
 }
@@ -406,6 +654,7 @@ static struct dvb_frontend_ops zl10353_ops = {
 	.write = zl10353_write,
 
 	.set_frontend = zl10353_set_parameters,
+	.get_frontend = zl10353_get_parameters,
 	.get_tune_settings = zl10353_get_tune_settings,
 
 	.read_status = zl10353_read_status,

+ 5 - 4
drivers/media/dvb/frontends/zl10353.h

@@ -1,7 +1,7 @@
 /*
  *  Driver for Zarlink DVB-T ZL10353 demodulator
  *
- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
  *
  *  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
@@ -29,8 +29,9 @@ struct zl10353_config
 	/* demodulator's I2C address */
 	u8 demod_address;
 
-	/* frequencies in kHz */
-	int adc_clock;	/* default: 45056 */
+	/* frequencies in units of 0.1kHz */
+	int adc_clock;	/* default: 450560 (45.056  MHz) */
+	int if2;	/* default: 361667 (36.1667 MHz) */
 
 	/* set if no pll is connected to the secondary i2c bus */
 	int no_tuner;
@@ -49,6 +50,6 @@ static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *c
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
 	return NULL;
 }
-#endif // CONFIG_DVB_ZL10353
+#endif /* CONFIG_DVB_ZL10353 */
 
 #endif /* ZL10353_H */

+ 21 - 2
drivers/media/dvb/frontends/zl10353_priv.h

@@ -1,7 +1,7 @@
 /*
  *  Driver for Zarlink DVB-T ZL10353 demodulator
  *
- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *  Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
  *
  *  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
@@ -16,7 +16,7 @@
  *
  *  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.=
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef _ZL10353_PRIV_
@@ -46,9 +46,28 @@ enum zl10353_reg_addr {
 	RS_ERR_CNT_0       = 0x13,
 	RS_UBC_1           = 0x14,
 	RS_UBC_0           = 0x15,
+	TPS_RECEIVED_1     = 0x1D,
+	TPS_RECEIVED_0     = 0x1E,
+	TPS_CURRENT_1      = 0x1F,
+	TPS_CURRENT_0      = 0x20,
+	RESET              = 0x55,
+	AGC_TARGET         = 0x56,
+	MCLK_RATIO         = 0x5C,
+	ACQ_CTL            = 0x5E,
 	TRL_NOMINAL_RATE_1 = 0x65,
 	TRL_NOMINAL_RATE_0 = 0x66,
+	INPUT_FREQ_1       = 0x6C,
+	INPUT_FREQ_0       = 0x6D,
+	TPS_GIVEN_1        = 0x6E,
+	TPS_GIVEN_0        = 0x6F,
+	TUNER_GO           = 0x70,
+	FSM_GO             = 0x71,
 	CHIP_ID            = 0x7F,
+	CHAN_STEP_1        = 0xE4,
+	CHAN_STEP_0        = 0xE5,
+	OFDM_LOCK_TIME     = 0xE7,
+	FEC_LOCK_TIME      = 0xE8,
+	ACQ_DELAY          = 0xE9,
 };
 
 #endif                          /* _ZL10353_PRIV_ */

+ 26 - 11
drivers/media/dvb/ttpci/Kconfig

@@ -1,8 +1,14 @@
+config TTPCI_EEPROM
+	tristate
+	default n
+
 config DVB_AV7110
 	tristate "AV7110 cards"
-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+	depends on DVB_CORE && PCI && I2C
 	select FW_LOADER if !DVB_AV7110_FIRMWARE
+	select TTPCI_EEPROM
 	select VIDEO_SAA7146_VV
+	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
@@ -57,10 +63,19 @@ config DVB_AV7110_OSD
 
 	  All other people say N.
 
+config DVB_BUDGET_CORE
+	tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
+	depends on DVB_CORE && PCI && I2C
+	select VIDEO_SAA7146
+	select TTPCI_EEPROM
+	help
+	  Support for simple SAA7146 based DVB cards
+	  (so called Budget- or Nova-PCI cards) without onboard
+	  MPEG2 decoder.
+
 config DVB_BUDGET
 	tristate "Budget cards"
-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
-	select VIDEO_SAA7146
+	depends on DVB_BUDGET_CORE && I2C
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
@@ -73,9 +88,9 @@ config DVB_BUDGET
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	help
-	  Support for simple SAA7146 based DVB cards
-	  (so called Budget- or Nova-PCI cards) without onboard
-	  MPEG2 decoder.
+	  Support for simple SAA7146 based DVB cards (so called Budget-
+	  or Nova-PCI cards) without onboard MPEG2 decoder, and without
+	  analog inputs or an onboard Common Interface connector.
 
 	  Say Y if you own such a card and want to use it.
 
@@ -84,8 +99,7 @@ config DVB_BUDGET
 
 config DVB_BUDGET_CI
 	tristate "Budget cards with onboard CI connector"
-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT
-	select VIDEO_SAA7146
+	depends on DVB_BUDGET_CORE && I2C
 	select DVB_STV0297 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
@@ -106,8 +120,9 @@ config DVB_BUDGET_CI
 
 config DVB_BUDGET_AV
 	tristate "Budget cards with analog video inputs"
-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+	depends on DVB_BUDGET_CORE && I2C
 	select VIDEO_SAA7146_VV
+	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
 	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
@@ -127,8 +142,8 @@ config DVB_BUDGET_AV
 
 config DVB_BUDGET_PATCH
 	tristate "AV7110 cards with Budget Patch"
-	depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
-	select DVB_AV7110
+	depends on DVB_BUDGET_CORE && I2C
+	depends on DVB_AV7110
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
 	select DVB_TDA8083 if !DVB_FE_CUSTOMISE

+ 7 - 5
drivers/media/dvb/ttpci/Makefile

@@ -5,11 +5,13 @@
 
 dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o
 
-obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
+obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
+obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
+obj-$(CONFIG_DVB_BUDGET) += budget.o
+obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
+obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
+obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
+obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 

+ 2 - 1
drivers/media/dvb/ttpci/av7110.c

@@ -2595,7 +2595,8 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
 	mutex_init(&av7110->osd_mutex);
 
 	/* TV standard */
-	av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL;
+	av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC
+					   : AV7110_VIDEO_MODE_PAL;
 
 	/* ARM "watchdog" */
 	init_waitqueue_head(&av7110->arm_wait);

+ 6 - 1
drivers/media/dvb/ttpci/av7110.h

@@ -46,6 +46,11 @@ extern int av7110_debug;
 
 enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM};
 
+enum av7110_video_mode {
+	AV7110_VIDEO_MODE_PAL 	= 0,
+	AV7110_VIDEO_MODE_NTSC	= 1
+};
+
 struct av7110_p2t {
 	u8		  pes[TS_SIZE];
 	u8		  counter;
@@ -170,7 +175,7 @@ struct av7110 {
 
 	ca_slot_info_t		ci_slot[2];
 
-	int			vidmode;
+	enum av7110_video_mode	vidmode;
 	struct dmxdev		dmxdev;
 	struct dvb_demux	demux;
 

+ 10 - 6
drivers/media/dvb/ttpci/av7110_av.c

@@ -329,7 +329,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
 	return 0;
 }
 
-int av7110_set_vidmode(struct av7110 *av7110, int mode)
+int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
 {
 	int ret;
 	dprintk(2, "av7110:%p, \n", av7110);
@@ -348,11 +348,15 @@ int av7110_set_vidmode(struct av7110 *av7110, int mode)
 }
 
 
-static int sw2mode[16] = {
-	VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL,
-	VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC,
-	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
-	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
+static enum av7110_video_mode sw2mode[16] = {
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
+	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
 };
 
 static int get_video_format(struct av7110 *av7110, u8 *buf, int count)

+ 2 - 1
drivers/media/dvb/ttpci/av7110_av.h

@@ -3,7 +3,8 @@
 
 struct av7110;
 
-extern int av7110_set_vidmode(struct av7110 *av7110, int mode);
+extern int av7110_set_vidmode(struct av7110 *av7110,
+			      enum av7110_video_mode mode);
 
 extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
 extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);

+ 2 - 2
drivers/media/dvb/ttpci/av7110_v4l.c

@@ -876,11 +876,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
 
 	if (std->id & V4L2_STD_PAL) {
-		av7110->vidmode = VIDEO_MODE_PAL;
+		av7110->vidmode = AV7110_VIDEO_MODE_PAL;
 		av7110_set_vidmode(av7110, av7110->vidmode);
 	}
 	else if (std->id & V4L2_STD_NTSC) {
-		av7110->vidmode = VIDEO_MODE_NTSC;
+		av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
 		av7110_set_vidmode(av7110, av7110->vidmode);
 	}
 	else

+ 10 - 0
drivers/media/radio/Kconfig

@@ -351,4 +351,14 @@ config USB_DSBR
 	  To compile this driver as a module, choose M here: the
 	  module will be called dsbr100.
 
+config USB_SI470X
+	tristate "Silicon Labs Si470x FM Radio Receiver support"
+	depends on USB && VIDEO_V4L2
+	---help---
+	  Say Y here if you want to connect this type of radio to your
+	  computer's USB port.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called radio-silabs.
+
 endif # RADIO_ADAPTERS

+ 1 - 0
drivers/media/radio/Makefile

@@ -21,5 +21,6 @@ obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
+obj-$(CONFIG_USB_SI470X) += radio-si470x.o
 
 EXTRA_CFLAGS += -Isound

+ 13 - 5
drivers/media/radio/dsbr100.c

@@ -33,6 +33,9 @@
 
  History:
 
+ Version 0.43:
+	Oliver Neukum: avoided DMA coherency issue
+
  Version 0.42:
 	Converted dsbr100 to use video_ioctl2
 	by Douglas Landgraf <dougsland@gmail.com>
@@ -135,7 +138,7 @@ module_param(radio_nr, int, 0);
 struct dsbr100_device {
 	struct usb_device *usbdev;
 	struct video_device *videodev;
-	unsigned char transfer_buffer[TB_LEN];
+	u8 *transfer_buffer;
 	int curfreq;
 	int stereo;
 	int users;
@@ -237,10 +240,7 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
 /* handle unplugging of the device, release data structures
 if nothing keeps us from doing it.  If something is still
 keeping us busy, the release callback of v4l will take care
-of releasing it.  stv680.c does not relase its private
-data, so I don't do this here either.  Checking out the
-code I'd expect I better did that, but if there's a memory
-leak here it's tiny (~50 bytes per disconnect) */
+of releasing it. */
 static void usb_dsbr100_disconnect(struct usb_interface *intf)
 {
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
@@ -250,6 +250,7 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
 		video_unregister_device(radio->videodev);
 		radio->videodev = NULL;
 		if (radio->users) {
+			kfree(radio->transfer_buffer);
 			kfree(radio);
 		} else {
 			radio->removed = 1;
@@ -425,6 +426,7 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file)
 		return -ENODEV;
 	radio->users = 0;
 	if (radio->removed) {
+		kfree(radio->transfer_buffer);
 		kfree(radio);
 	}
 	return 0;
@@ -471,7 +473,12 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 
 	if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
 		return -ENOMEM;
+	if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) {
+		kfree(radio);
+		return -ENOMEM;
+	}
 	if (!(radio->videodev = video_device_alloc())) {
+		kfree(radio->transfer_buffer);
 		kfree(radio);
 		return -ENOMEM;
 	}
@@ -485,6 +492,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 	if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
 		warn("Could not register video device");
 		video_device_release(radio->videodev);
+		kfree(radio->transfer_buffer);
 		kfree(radio);
 		return -EIO;
 	}

+ 3 - 3
drivers/media/radio/radio-gemtek.c

@@ -58,10 +58,10 @@ static int initmute	= 1;
 static int radio_nr	= -1;
 
 module_param(io, int, 0444);
-MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic"
+MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
 	 "probing is disabled or fails. The most common I/O ports are: 0x20c "
 	 "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
-	 " work for the combined sound/radiocard).");
+	 "work for the combined sound/radiocard).");
 
 module_param(probe, bool, 0444);
 MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
@@ -392,7 +392,7 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 	}
 };
 
-static struct file_operations gemtek_fops = {
+static const struct file_operations gemtek_fops = {
 	.owner		= THIS_MODULE,
 	.open		= video_exclusive_open,
 	.release	= video_exclusive_release,

+ 1 - 1
drivers/media/radio/radio-maestro.c

@@ -423,7 +423,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
 errunr:
 	video_unregister_device(maestro_radio_inst);
 errfr1:
-	kfree(maestro_radio_inst);
+	video_device_release(maestro_radio_inst);
 errfr:
 	kfree(radio_unit);
 err:

+ 1 - 1
drivers/media/radio/radio-sf16fmi.c

@@ -321,7 +321,7 @@ static struct isapnp_device_id id_table[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(isapnp, id_table);
 
-static int isapnp_fmi_probe(void)
+static int __init isapnp_fmi_probe(void)
 {
 	int i = 0;
 

+ 1 - 2
drivers/media/radio/radio-sf16fmr2.c

@@ -476,8 +476,7 @@ static int __init fmr2_init(void)
 		return -EBUSY;
 	}
 
-	if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-	{
+	if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 2);
 		return -EINVAL;
 	}

+ 1432 - 0
drivers/media/radio/radio-si470x.c

@@ -0,0 +1,1432 @@
+/*
+ *  drivers/media/radio/radio-si470x.c
+ *
+ *  Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers:
+ *   - Silicon Labs USB FM Radio Reference Design
+ *   - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
+ *
+ *  Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net>
+ *
+ * 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
+ */
+
+
+/*
+ * History:
+ * 2008-01-12	Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.0
+ *		- First working version
+ * 2008-01-13   Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.1
+ *		- Improved error handling, every function now returns errno
+ *		- Improved multi user access (start/mute/stop)
+ *		- Channel doesn't get lost anymore after start/mute/stop
+ *		- RDS support added (polling mode via interrupt EP 1)
+ *		- marked default module parameters with *value*
+ *		- switched from bit structs to bit masks
+ *		- header file cleaned and integrated
+ * 2008-01-14	Tobias Lorenz <tobias.lorenz@gmx.net>
+ * 		Version 1.0.2
+ * 		- hex values are now lower case
+ * 		- commented USB ID for ADS/Tech moved on todo list
+ * 		- blacklisted si470x in hid-quirks.c
+ * 		- rds buffer handling functions integrated into *_work, *_read
+ * 		- rds_command in si470x_poll exchanged against simple retval
+ * 		- check for firmware version 15
+ * 		- code order and prototypes still remain the same
+ * 		- spacing and bottom of band codes remain the same
+ * 2008-01-16	Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.3
+ * 		- code reordered to avoid function prototypes
+ *		- switch/case defaults are now more user-friendly
+ *		- unified comment style
+ *		- applied all checkpatch.pl v1.12 suggestions
+ *		  except the warning about the too long lines with bit comments
+ *		- renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
+ * 2008-01-22	Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.4
+ *		- avoid poss. locking when doing copy_to_user which may sleep
+ *		- RDS is automatically activated on read now
+ *		- code cleaned of unnecessary rds_commands
+ *		- USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
+ *		  (thanks to Guillaume RAMOUSSE)
+ *
+ * ToDo:
+ * - add seeking support
+ * - add firmware download/update support
+ * - RDS support: interrupt mode, instead of polling
+ * - add LED status output (check if that's not already done in firmware)
+ */
+
+
+/* driver definitions */
+#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
+#define DRIVER_NAME "radio-si470x"
+#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4)
+#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
+#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
+
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/rds.h>
+
+
+/* USB Device ID List */
+static struct usb_device_id si470x_usb_driver_id_table[] = {
+	/* Silicon Labs USB FM Radio Reference Design */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a,	USB_CLASS_HID, 0, 0) },
+	/* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155,	USB_CLASS_HID, 0, 0) },
+	/* Terminating entry */
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
+
+
+
+/**************************************************************************
+ * Module Parameters
+ **************************************************************************/
+
+/* Radio Nr */
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+
+/* Spacing (kHz) */
+/* 0: 200 kHz (USA, Australia) */
+/* 1: 100 kHz (Europe, Japan) */
+/* 2:  50 kHz */
+static int space = 2;
+module_param(space, int, 0);
+MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
+
+/* Bottom of Band (MHz) */
+/* 0: 87.5 - 108 MHz (USA, Europe)*/
+/* 1: 76   - 108 MHz (Japan wide band) */
+/* 2: 76   -  90 MHz (Japan) */
+static int band = 1;
+module_param(band, int, 0);
+MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
+
+/* De-emphasis */
+/* 0: 75 us (USA) */
+/* 1: 50 us (Europe, Australia, Japan) */
+static int de = 1;
+module_param(de, int, 0);
+MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*");
+
+/* USB timeout */
+static int usb_timeout = 500;
+module_param(usb_timeout, int, 0);
+MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
+
+/* Seek retries */
+static int seek_retries = 100;
+module_param(seek_retries, int, 0);
+MODULE_PARM_DESC(seek_retries, "Seek retries: *100*");
+
+/* RDS buffer blocks */
+static int rds_buf = 100;
+module_param(rds_buf, int, 0);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
+
+/* RDS maximum block errors */
+static int max_rds_errors = 1;
+/* 0 means   0  errors requiring correction */
+/* 1 means 1-2  errors requiring correction (used by original USBRadio.exe) */
+/* 2 means 3-5  errors requiring correction */
+/* 3 means   6+ errors or errors in checkword, correction not possible */
+module_param(max_rds_errors, int, 0);
+MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
+
+/* RDS poll frequency */
+static int rds_poll_time = 40;
+/* 40 is used by the original USBRadio.exe */
+/* 50 is used by radio-cadet */
+/* 75 should be okay */
+/* 80 is the usual RDS receive interval */
+module_param(rds_poll_time, int, 0);
+MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
+
+
+
+/**************************************************************************
+ * Register Definitions
+ **************************************************************************/
+#define RADIO_REGISTER_SIZE	2	/* 16 register bit width */
+#define RADIO_REGISTER_NUM	16	/* DEVICEID   ... RDSD */
+#define RDS_REGISTER_NUM	6	/* STATUSRSSI ... RDSD */
+
+#define DEVICEID		0	/* Device ID */
+#define DEVICEID_PN		0xf000	/* bits 15..12: Part Number */
+#define DEVICEID_MFGID		0x0fff	/* bits 11..00: Manufacturer ID */
+
+#define CHIPID			1	/* Chip ID */
+#define CHIPID_REV		0xfc00	/* bits 15..10: Chip Version */
+#define CHIPID_DEV		0x0200	/* bits 09..09: Device */
+#define CHIPID_FIRMWARE		0x01ff	/* bits 08..00: Firmware Version */
+
+#define POWERCFG		2	/* Power Configuration */
+#define POWERCFG_DSMUTE		0x8000	/* bits 15..15: Softmute Disable */
+#define POWERCFG_DMUTE		0x4000	/* bits 14..14: Mute Disable */
+#define POWERCFG_MONO		0x2000	/* bits 13..13: Mono Select */
+#define POWERCFG_RDSM		0x0800	/* bits 11..11: RDS Mode (Si4701 only) */
+#define POWERCFG_SKMODE		0x0400	/* bits 10..10: Seek Mode */
+#define POWERCFG_SEEKUP		0x0200	/* bits 09..09: Seek Direction */
+#define POWERCFG_SEEK		0x0100	/* bits 08..08: Seek */
+#define POWERCFG_DISABLE	0x0040	/* bits 06..06: Powerup Disable */
+#define POWERCFG_ENABLE		0x0001	/* bits 00..00: Powerup Enable */
+
+#define CHANNEL			3	/* Channel */
+#define CHANNEL_TUNE		0x8000	/* bits 15..15: Tune */
+#define CHANNEL_CHAN		0x03ff	/* bits 09..00: Channel Select */
+
+#define SYSCONFIG1		4	/* System Configuration 1 */
+#define SYSCONFIG1_RDSIEN	0x8000	/* bits 15..15: RDS Interrupt Enable (Si4701 only) */
+#define SYSCONFIG1_STCIEN	0x4000	/* bits 14..14: Seek/Tune Complete Interrupt Enable */
+#define SYSCONFIG1_RDS		0x1000	/* bits 12..12: RDS Enable (Si4701 only) */
+#define SYSCONFIG1_DE		0x0800	/* bits 11..11: De-emphasis (0=75us 1=50us) */
+#define SYSCONFIG1_AGCD		0x0400	/* bits 10..10: AGC Disable */
+#define SYSCONFIG1_BLNDADJ	0x00c0	/* bits 07..06: Stereo/Mono Blend Level Adjustment */
+#define SYSCONFIG1_GPIO3	0x0030	/* bits 05..04: General Purpose I/O 3 */
+#define SYSCONFIG1_GPIO2	0x000c	/* bits 03..02: General Purpose I/O 2 */
+#define SYSCONFIG1_GPIO1	0x0003	/* bits 01..00: General Purpose I/O 1 */
+
+#define SYSCONFIG2		5	/* System Configuration 2 */
+#define SYSCONFIG2_SEEKTH	0xff00	/* bits 15..08: RSSI Seek Threshold */
+#define SYSCONFIG2_BAND		0x0080	/* bits 07..06: Band Select */
+#define SYSCONFIG2_SPACE	0x0030	/* bits 05..04: Channel Spacing */
+#define SYSCONFIG2_VOLUME	0x000f	/* bits 03..00: Volume */
+
+#define SYSCONFIG3		6	/* System Configuration 3 */
+#define SYSCONFIG3_SMUTER	0xc000	/* bits 15..14: Softmute Attack/Recover Rate */
+#define SYSCONFIG3_SMUTEA	0x3000	/* bits 13..12: Softmute Attenuation */
+#define SYSCONFIG3_SKSNR	0x00f0	/* bits 07..04: Seek SNR Threshold */
+#define SYSCONFIG3_SKCNT	0x000f	/* bits 03..00: Seek FM Impulse Detection Threshold */
+
+#define TEST1			7	/* Test 1 */
+#define TEST1_AHIZEN		0x4000	/* bits 14..14: Audio High-Z Enable */
+
+#define TEST2			8	/* Test 2 */
+/* TEST2 only contains reserved bits */
+
+#define BOOTCONFIG		9	/* Boot Configuration */
+/* BOOTCONFIG only contains reserved bits */
+
+#define STATUSRSSI		10	/* Status RSSI */
+#define STATUSRSSI_RDSR		0x8000	/* bits 15..15: RDS Ready (Si4701 only) */
+#define STATUSRSSI_STC		0x4000	/* bits 14..14: Seek/Tune Complete */
+#define STATUSRSSI_SF		0x2000	/* bits 13..13: Seek Fail/Band Limit */
+#define STATUSRSSI_AFCRL	0x1000	/* bits 12..12: AFC Rail */
+#define STATUSRSSI_RDSS		0x0800	/* bits 11..11: RDS Synchronized (Si4701 only) */
+#define STATUSRSSI_BLERA	0x0600	/* bits 10..09: RDS Block A Errors (Si4701 only) */
+#define STATUSRSSI_ST		0x0100	/* bits 08..08: Stereo Indicator */
+#define STATUSRSSI_RSSI		0x00ff	/* bits 07..00: RSSI (Received Signal Strength Indicator) */
+
+#define READCHAN		11	/* Read Channel */
+#define READCHAN_BLERB		0xc000	/* bits 15..14: RDS Block D Errors (Si4701 only) */
+#define READCHAN_BLERC		0x3000	/* bits 13..12: RDS Block C Errors (Si4701 only) */
+#define READCHAN_BLERD		0x0c00	/* bits 11..10: RDS Block B Errors (Si4701 only) */
+#define READCHAN_READCHAN	0x03ff	/* bits 09..00: Read Channel */
+
+#define RDSA			12	/* RDSA */
+#define RDSA_RDSA		0xffff	/* bits 15..00: RDS Block A Data (Si4701 only) */
+
+#define RDSB			13	/* RDSB */
+#define RDSB_RDSB		0xffff	/* bits 15..00: RDS Block B Data (Si4701 only) */
+
+#define RDSC			14	/* RDSC */
+#define RDSC_RDSC		0xffff	/* bits 15..00: RDS Block C Data (Si4701 only) */
+
+#define RDSD			15	/* RDSD */
+#define RDSD_RDSD		0xffff	/* bits 15..00: RDS Block D Data (Si4701 only) */
+
+
+
+/**************************************************************************
+ * USB HID Reports
+ **************************************************************************/
+
+/* Reports 1-16 give direct read/write access to the 16 Si470x registers */
+/* with the (REPORT_ID - 1) corresponding to the register address across USB */
+/* endpoint 0 using GET_REPORT and SET_REPORT */
+#define REGISTER_REPORT_SIZE	(RADIO_REGISTER_SIZE + 1)
+#define REGISTER_REPORT(reg)	((reg) + 1)
+
+/* Report 17 gives direct read/write access to the entire Si470x register */
+/* map across endpoint 0 using GET_REPORT and SET_REPORT */
+#define ENTIRE_REPORT_SIZE	(RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
+#define ENTIRE_REPORT		17
+
+/* Report 18 is used to send the lowest 6 Si470x registers up the HID */
+/* interrupt endpoint 1 to Windows every 20 milliseconds for status */
+#define RDS_REPORT_SIZE		(RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
+#define RDS_REPORT		18
+
+/* Report 19: LED state */
+#define LED_REPORT_SIZE		3
+#define LED_REPORT		19
+
+/* Report 19: stream */
+#define STREAM_REPORT_SIZE	3
+#define	STREAM_REPORT		19
+
+/* Report 20: scratch */
+#define SCRATCH_PAGE_SIZE	63
+#define SCRATCH_REPORT_SIZE	(SCRATCH_PAGE_SIZE + 1)
+#define SCRATCH_REPORT		20
+
+/* Reports 19-22: flash upgrade of the C8051F321 */
+#define WRITE_REPORT		19
+#define FLASH_REPORT		20
+#define CRC_REPORT		21
+#define RESPONSE_REPORT		22
+
+/* Report 23: currently unused, but can accept 60 byte reports on the HID */
+/* interrupt out endpoint 2 every 1 millisecond */
+#define UNUSED_REPORT		23
+
+
+
+/**************************************************************************
+ * Software/Hardware Versions
+ **************************************************************************/
+#define RADIO_SW_VERSION_NOT_BOOTLOADABLE	6
+#define RADIO_SW_VERSION			7
+#define RADIO_SW_VERSION_CURRENT		15
+#define RADIO_HW_VERSION			1
+
+#define SCRATCH_PAGE_SW_VERSION	1
+#define SCRATCH_PAGE_HW_VERSION	2
+
+
+
+/**************************************************************************
+ * LED State Definitions
+ **************************************************************************/
+#define LED_COMMAND		0x35
+
+#define NO_CHANGE_LED		0x00
+#define ALL_COLOR_LED		0x01	/* streaming state */
+#define BLINK_GREEN_LED		0x02	/* connect state */
+#define BLINK_RED_LED		0x04
+#define BLINK_ORANGE_LED	0x10	/* disconnect state */
+#define SOLID_GREEN_LED		0x20	/* tuning/seeking state */
+#define SOLID_RED_LED		0x40	/* bootload state */
+#define SOLID_ORANGE_LED	0x80
+
+
+
+/**************************************************************************
+ * Stream State Definitions
+ **************************************************************************/
+#define STREAM_COMMAND	0x36
+#define STREAM_VIDPID	0x00
+#define STREAM_AUDIO	0xff
+
+
+
+/**************************************************************************
+ * Bootloader / Flash Commands
+ **************************************************************************/
+
+/* unique id sent to bootloader and required to put into a bootload state */
+#define UNIQUE_BL_ID		0x34
+
+/* mask for the flash data */
+#define FLASH_DATA_MASK		0x55
+
+/* bootloader commands */
+#define GET_SW_VERSION_COMMAND	0x00
+#define	SET_PAGE_COMMAND	0x01
+#define ERASE_PAGE_COMMAND	0x02
+#define WRITE_PAGE_COMMAND	0x03
+#define CRC_ON_PAGE_COMMAND	0x04
+#define READ_FLASH_BYTE_COMMAND	0x05
+#define RESET_DEVICE_COMMAND	0x06
+#define GET_HW_VERSION_COMMAND	0x07
+#define BLANK			0xff
+
+/* bootloader command responses */
+#define COMMAND_OK		0x01
+#define COMMAND_FAILED		0x02
+#define COMMAND_PENDING		0x03
+
+/* buffer sizes */
+#define COMMAND_BUFFER_SIZE	4
+#define RESPONSE_BUFFER_SIZE	2
+#define FLASH_BUFFER_SIZE	64
+#define CRC_BUFFER_SIZE		3
+
+
+
+/**************************************************************************
+ * General Driver Definitions
+ **************************************************************************/
+
+/*
+ * si470x_device - private data
+ */
+struct si470x_device {
+	/* reference to USB and video device */
+	struct usb_device *usbdev;
+	struct video_device *videodev;
+
+	/* are these really necessary ? */
+	int users;
+
+	/* report buffer (maximum 64 bytes) */
+	unsigned char buf[64];
+
+	/* Silabs internal registers (0..15) */
+	unsigned short registers[RADIO_REGISTER_NUM];
+
+	/* RDS receive buffer */
+	struct work_struct work;
+	wait_queue_head_t read_queue;
+	struct timer_list timer;
+	spinlock_t lock;		/* buffer locking */
+	unsigned char *buffer;		/* size is always multiple of three */
+	unsigned int buf_size;
+	unsigned int rd_index;
+	unsigned int wr_index;
+};
+
+
+/*
+ * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
+ * 62.5 kHz otherwise.
+ * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
+ * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
+ * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
+ */
+#define FREQ_MUL (1000000 / 62.5)
+
+
+
+/**************************************************************************
+ * General Driver Functions
+ **************************************************************************/
+
+/*
+ * si470x_get_report - receive a HID report
+ */
+static int si470x_get_report(struct si470x_device *radio, int size)
+{
+	return usb_control_msg(radio->usbdev,
+		usb_rcvctrlpipe(radio->usbdev, 0),
+		HID_REQ_GET_REPORT,
+		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+		radio->buf[0], 2,
+		radio->buf, size, usb_timeout);
+}
+
+
+/*
+ * si470x_set_report - send a HID report
+ */
+static int si470x_set_report(struct si470x_device *radio, int size)
+{
+	return usb_control_msg(radio->usbdev,
+		usb_sndctrlpipe(radio->usbdev, 0),
+		HID_REQ_SET_REPORT,
+		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+		radio->buf[0], 2,
+		radio->buf, size, usb_timeout);
+}
+
+
+/*
+ * si470x_get_register - read register
+ */
+static int si470x_get_register(struct si470x_device *radio, int regnr)
+{
+	int retval;
+
+	radio->buf[0] = REGISTER_REPORT(regnr);
+
+	retval = si470x_get_report(radio, REGISTER_REPORT_SIZE);
+	if (retval >= 0)
+		radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2];
+
+	return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_set_register - write register
+ */
+static int si470x_set_register(struct si470x_device *radio, int regnr)
+{
+	int retval;
+
+	radio->buf[0] = REGISTER_REPORT(regnr);
+	radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8;
+	radio->buf[2] = (radio->registers[regnr] & 0x00ff);
+
+	retval = si470x_set_report(radio, REGISTER_REPORT_SIZE);
+
+	return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_get_all_registers - read entire registers
+ */
+static int si470x_get_all_registers(struct si470x_device *radio)
+{
+	int retval;
+	int regnr;
+
+	radio->buf[0] = ENTIRE_REPORT;
+
+	retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE);
+
+	if (retval >= 0)
+		for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
+			radio->registers[regnr] =
+			(radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
+			 radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
+
+	return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_get_rds_registers - read rds registers
+ */
+static int si470x_get_rds_registers(struct si470x_device *radio)
+{
+	int retval;
+	int regnr;
+	int size;
+
+	radio->buf[0] = RDS_REPORT;
+
+	retval = usb_interrupt_msg(radio->usbdev,
+		usb_rcvctrlpipe(radio->usbdev, 1),
+		radio->buf, RDS_REPORT_SIZE, &size, usb_timeout);
+
+	if (retval >= 0)
+		for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
+			radio->registers[STATUSRSSI + regnr] =
+			(radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
+			 radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
+
+	return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_set_chan - set the channel
+ */
+static int si470x_set_chan(struct si470x_device *radio, int chan)
+{
+	int retval, i;
+
+	/* start tuning */
+	radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
+	radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
+	retval = si470x_set_register(radio, CHANNEL);
+	if (retval < 0)
+		return retval;
+
+	/* wait till seek operation has completed */
+	i = 0;
+	do {
+		retval = si470x_get_register(radio, STATUSRSSI);
+		if (retval < 0)
+			return retval;
+	} while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) &&
+		(++i < seek_retries));
+	if (i >= seek_retries)
+		printk(KERN_WARNING DRIVER_NAME
+			": seek does not finish after %d tries\n", i);
+
+	/* stop tuning */
+	radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
+	return si470x_set_register(radio, CHANNEL);
+}
+
+
+/*
+ * si470x_get_freq - get the frequency
+ */
+static int si470x_get_freq(struct si470x_device *radio)
+{
+	int spacing, band_bottom, chan, freq;
+	int retval;
+
+	/* Spacing (kHz) */
+	switch (space) {
+	/* 0: 200 kHz (USA, Australia) */
+	case 0 : spacing = 0.200 * FREQ_MUL; break;
+	/* 1: 100 kHz (Europe, Japan) */
+	case 1 : spacing = 0.100 * FREQ_MUL; break;
+	/* 2:  50 kHz */
+	default: spacing = 0.050 * FREQ_MUL; break;
+	};
+
+	/* Bottom of Band (MHz) */
+	switch (band) {
+	/* 0: 87.5 - 108 MHz (USA, Europe) */
+	case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+	/* 1: 76   - 108 MHz (Japan wide band) */
+	default: band_bottom = 76   * FREQ_MUL; break;
+	/* 2: 76   -  90 MHz (Japan) */
+	case 2 : band_bottom = 76   * FREQ_MUL; break;
+	};
+
+	/* read channel */
+	retval = si470x_get_register(radio, READCHAN);
+	if (retval < 0)
+		return retval;
+	chan = radio->registers[READCHAN] & READCHAN_READCHAN;
+
+	/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
+	freq = chan * spacing + band_bottom;
+
+	return freq;
+}
+
+
+/*
+ * si470x_set_freq - set the frequency
+ */
+static int si470x_set_freq(struct si470x_device *radio, int freq)
+{
+	int spacing, band_bottom, chan;
+
+	/* Spacing (kHz) */
+	switch (space) {
+	/* 0: 200 kHz (USA, Australia) */
+	case 0 : spacing = 0.200 * FREQ_MUL; break;
+	/* 1: 100 kHz (Europe, Japan) */
+	case 1 : spacing = 0.100 * FREQ_MUL; break;
+	/* 2:  50 kHz */
+	default: spacing = 0.050 * FREQ_MUL; break;
+	};
+
+	/* Bottom of Band (MHz) */
+	switch (band) {
+	/* 0: 87.5 - 108 MHz (USA, Europe) */
+	case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+	/* 1: 76   - 108 MHz (Japan wide band) */
+	default: band_bottom = 76   * FREQ_MUL; break;
+	/* 2: 76   -  90 MHz (Japan) */
+	case 2 : band_bottom = 76   * FREQ_MUL; break;
+	};
+
+	/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
+	chan = (freq - band_bottom) / spacing;
+
+	return si470x_set_chan(radio, chan);
+}
+
+
+/*
+ * si470x_start - switch on radio
+ */
+static int si470x_start(struct si470x_device *radio)
+{
+	int retval;
+
+	/* powercfg */
+	radio->registers[POWERCFG] =
+		POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
+	retval = si470x_set_register(radio, POWERCFG);
+	if (retval < 0)
+		return retval;
+
+	/* sysconfig 1 */
+	radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
+	retval = si470x_set_register(radio, SYSCONFIG1);
+	if (retval < 0)
+		return retval;
+
+	/* sysconfig 2 */
+	radio->registers[SYSCONFIG2] =
+		(0x3f  << 8) |	/* SEEKTH */
+		(band  << 6) |	/* BAND */
+		(space << 4) |	/* SPACE */
+		15;		/* VOLUME (max) */
+	retval = si470x_set_register(radio, SYSCONFIG2);
+	if (retval < 0)
+		return retval;
+
+	/* reset last channel */
+	return si470x_set_chan(radio,
+		radio->registers[CHANNEL] & CHANNEL_CHAN);
+}
+
+
+/*
+ * si470x_stop - switch off radio
+ */
+static int si470x_stop(struct si470x_device *radio)
+{
+	int retval;
+
+	/* sysconfig 1 */
+	radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
+	retval = si470x_set_register(radio, SYSCONFIG1);
+	if (retval < 0)
+		return retval;
+
+	/* powercfg */
+	radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
+	/* POWERCFG_ENABLE has to automatically go low */
+	radio->registers[POWERCFG] |= POWERCFG_ENABLE |	POWERCFG_DISABLE;
+	return si470x_set_register(radio, POWERCFG);
+}
+
+
+/*
+ * si470x_rds_on - switch on rds reception
+ */
+static int si470x_rds_on(struct si470x_device *radio)
+{
+	/* sysconfig 1 */
+	radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
+	return si470x_set_register(radio, SYSCONFIG1);
+}
+
+
+
+/**************************************************************************
+ * RDS Driver Functions
+ **************************************************************************/
+
+/*
+ * si470x_rds - rds processing function
+ */
+static void si470x_rds(struct si470x_device *radio)
+{
+	unsigned char tmpbuf[3];
+	unsigned char blocknum;
+	unsigned char bler; /* rds block errors */
+	unsigned short rds;
+	unsigned int i;
+
+	/* get rds blocks */
+	if (si470x_get_rds_registers(radio) < 0)
+		return;
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
+		/* No RDS group ready */
+		return;
+	}
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
+		/* RDS decoder not synchronized */
+		return;
+	}
+
+	/* copy four RDS blocks to internal buffer */
+	if (spin_trylock(&radio->lock)) {
+		/* process each rds block */
+		for (blocknum = 0; blocknum < 4; blocknum++) {
+			switch (blocknum) {
+			default:
+				bler = (radio->registers[STATUSRSSI] &
+						STATUSRSSI_BLERA) >> 9;
+				rds = radio->registers[RDSA];
+				break;
+			case 1:
+				bler = (radio->registers[READCHAN] &
+						READCHAN_BLERB) >> 14;
+				rds = radio->registers[RDSB];
+				break;
+			case 2:
+				bler = (radio->registers[READCHAN] &
+						READCHAN_BLERC) >> 12;
+				rds = radio->registers[RDSC];
+				break;
+			case 3:
+				bler = (radio->registers[READCHAN] &
+						READCHAN_BLERD) >> 10;
+				rds = radio->registers[RDSD];
+				break;
+			};
+
+			/* Fill the V4L2 RDS buffer */
+			tmpbuf[0] = rds & 0x00ff;	/* LSB */
+			tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */
+			tmpbuf[2] = blocknum;		/* offset name */
+			tmpbuf[2] |= blocknum << 3;	/* received offset */
+			if (bler > max_rds_errors)
+				tmpbuf[2] |= 0x80; /* uncorrectable errors */
+			else if (bler > 0)
+				tmpbuf[2] |= 0x40; /* corrected error(s) */
+
+			/* copy RDS block to internal buffer */
+			for (i = 0; i < 3; i++) {
+				radio->buffer[radio->wr_index] = tmpbuf[i];
+				radio->wr_index++;
+			}
+
+			/* wrap write pointer */
+			if (radio->wr_index >= radio->buf_size)
+				radio->wr_index = 0;
+
+			/* check for overflow */
+			if (radio->wr_index == radio->rd_index) {
+				/* increment and wrap read pointer */
+				radio->rd_index += 3;
+				if (radio->rd_index >= radio->buf_size)
+					radio->rd_index = 0;
+			}
+		}
+		spin_unlock(&radio->lock);
+	}
+
+	/* wake up read queue */
+	if (radio->wr_index != radio->rd_index)
+		wake_up_interruptible(&radio->read_queue);
+}
+
+
+/*
+ * si470x_timer - rds timer function
+ */
+static void si470x_timer(unsigned long data)
+{
+	struct si470x_device *radio = (struct si470x_device *) data;
+
+	schedule_work(&radio->work);
+}
+
+
+/*
+ * si470x_work - rds work function
+ */
+static void si470x_work(struct work_struct *work)
+{
+	struct si470x_device *radio = container_of(work, struct si470x_device,
+		work);
+
+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+		return;
+
+	si470x_rds(radio);
+	mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time));
+}
+
+
+
+/**************************************************************************
+ * File Operations Interface
+ **************************************************************************/
+
+/*
+ * si470x_fops_read - read RDS data
+ */
+static ssize_t si470x_fops_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+	unsigned int block_count = 0;
+
+	/* switch on rds reception */
+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
+		si470x_rds_on(radio);
+		schedule_work(&radio->work);
+	}
+
+	/* block if no new data available */
+	while (radio->wr_index == radio->rd_index) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		interruptible_sleep_on(&radio->read_queue);
+	}
+
+	/* calculate block count from byte count */
+	count /= 3;
+
+	/* copy RDS block out of internal buffer and to user buffer */
+	if (spin_trylock(&radio->lock)) {
+		while (block_count < count) {
+			if (radio->rd_index == radio->wr_index)
+				break;
+
+			/* always transfer rds complete blocks */
+			if (copy_to_user(buf,
+					&radio->buffer[radio->rd_index], 3))
+				/* retval = -EFAULT; */
+				break;
+
+			/* increment and wrap read pointer */
+			radio->rd_index += 3;
+			if (radio->rd_index >= radio->buf_size)
+				radio->rd_index = 0;
+
+			/* increment counters */
+			block_count++;
+			buf += 3;
+			retval += 3;
+		}
+
+		spin_unlock(&radio->lock);
+	}
+
+	return retval;
+}
+
+
+/*
+ * si470x_fops_poll - poll RDS data
+ */
+static unsigned int si470x_fops_poll(struct file *file,
+		struct poll_table_struct *pts)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	/* switch on rds reception */
+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
+		si470x_rds_on(radio);
+		schedule_work(&radio->work);
+	}
+
+	poll_wait(file, &radio->read_queue, pts);
+
+	if (radio->rd_index != radio->wr_index)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+
+/*
+ * si470x_fops_open - file open
+ */
+static int si470x_fops_open(struct inode *inode, struct file *file)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	radio->users++;
+	if (radio->users == 1)
+		return si470x_start(radio);
+
+	return 0;
+}
+
+
+/*
+ * si470x_fops_release - file release
+ */
+static int si470x_fops_release(struct inode *inode, struct file *file)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (!radio)
+		return -ENODEV;
+
+	radio->users--;
+	if (radio->users == 0) {
+		/* stop rds reception */
+		del_timer_sync(&radio->timer);
+		flush_scheduled_work();
+
+		/* cancel read processes */
+		wake_up_interruptible(&radio->read_queue);
+
+		return si470x_stop(radio);
+	}
+
+	return 0;
+}
+
+
+/*
+ * si470x_fops - file operations interface
+ */
+static const struct file_operations si470x_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= si470x_fops_read,
+	.poll		= si470x_fops_poll,
+	.ioctl		= video_ioctl2,
+	.compat_ioctl	= v4l_compat_ioctl32,
+	.open		= si470x_fops_open,
+	.release	= si470x_fops_release,
+};
+
+
+
+/**************************************************************************
+ * Video4Linux Interface
+ **************************************************************************/
+
+/*
+ * si470x_v4l2_queryctrl - query control
+ */
+static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
+/* HINT: the disabled controls are only here to satify kradio and such apps */
+	{
+		.id		= V4L2_CID_AUDIO_VOLUME,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Volume",
+		.minimum	= 0,
+		.maximum	= 15,
+		.step		= 1,
+		.default_value	= 15,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_BALANCE,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_BASS,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_TREBLE,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_MUTE,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Mute",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 1,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_LOUDNESS,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+};
+
+
+/*
+ * si470x_vidioc_querycap - query device capabilities
+ */
+static int si470x_vidioc_querycap(struct file *file, void *priv,
+		struct v4l2_capability *capability)
+{
+	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+	sprintf(capability->bus_info, "USB");
+	capability->version = DRIVER_VERSION;
+	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_g_input - get input
+ */
+static int si470x_vidioc_g_input(struct file *filp, void *priv,
+		unsigned int *i)
+{
+	*i = 0;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_input - set input
+ */
+static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_queryctrl - enumerate control items
+ */
+static int si470x_vidioc_queryctrl(struct file *file, void *priv,
+		struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
+		if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) {
+			memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+
+/*
+ * si470x_vidioc_g_ctrl - get the value of a control
+ */
+static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		ctrl->value = radio->registers[SYSCONFIG2] &
+				SYSCONFIG2_VOLUME;
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = ((radio->registers[POWERCFG] &
+				POWERCFG_DMUTE) == 0) ? 1 : 0;
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_ctrl - set the value of a control
+ */
+static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
+		radio->registers[SYSCONFIG2] |= ctrl->value;
+		return si470x_set_register(radio, SYSCONFIG2);
+	case V4L2_CID_AUDIO_MUTE:
+		if (ctrl->value == 1)
+			radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
+		else
+			radio->registers[POWERCFG] |= POWERCFG_DMUTE;
+		return si470x_set_register(radio, POWERCFG);
+	}
+
+	return -EINVAL;
+}
+
+
+/*
+ * si470x_vidioc_g_audio - get audio attributes
+ */
+static int si470x_vidioc_g_audio(struct file *file, void *priv,
+		struct v4l2_audio *audio)
+{
+	if (audio->index > 1)
+		return -EINVAL;
+
+	strcpy(audio->name, "Radio");
+	audio->capability = V4L2_AUDCAP_STEREO;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_audio - set audio attributes
+ */
+static int si470x_vidioc_s_audio(struct file *file, void *priv,
+		struct v4l2_audio *audio)
+{
+	if (audio->index != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_g_tuner - get tuner attributes
+ */
+static int si470x_vidioc_g_tuner(struct file *file, void *priv,
+		struct v4l2_tuner *tuner)
+{
+	int retval;
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (tuner->index > 0)
+		return -EINVAL;
+
+	/* read status rssi */
+	retval = si470x_get_register(radio, STATUSRSSI);
+	if (retval < 0)
+		return retval;
+
+	strcpy(tuner->name, "FM");
+	tuner->type = V4L2_TUNER_RADIO;
+	switch (band) {
+	/* 0: 87.5 - 108 MHz (USA, Europe, default) */
+	default:
+		tuner->rangelow  =  87.5 * FREQ_MUL;
+		tuner->rangehigh = 108   * FREQ_MUL;
+		break;
+	/* 1: 76   - 108 MHz (Japan wide band) */
+	case 1 :
+		tuner->rangelow  =  76   * FREQ_MUL;
+		tuner->rangehigh = 108   * FREQ_MUL;
+		break;
+	/* 2: 76   -  90 MHz (Japan) */
+	case 2 :
+		tuner->rangelow  =  76   * FREQ_MUL;
+		tuner->rangehigh =  90   * FREQ_MUL;
+		break;
+	};
+	tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	tuner->capability = V4L2_TUNER_CAP_LOW;
+
+	/* Stereo indicator == Stereo (instead of Mono) */
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
+		tuner->audmode = V4L2_TUNER_MODE_STEREO;
+	else
+		tuner->audmode = V4L2_TUNER_MODE_MONO;
+
+	/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
+	tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
+				* 0x0101;
+
+	/* automatic frequency control: -1: freq to low, 1 freq to high */
+	tuner->afc = 0;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_tuner - set tuner attributes
+ */
+static int si470x_vidioc_s_tuner(struct file *file, void *priv,
+		struct v4l2_tuner *tuner)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (tuner->index > 0)
+		return -EINVAL;
+
+	if (tuner->audmode == V4L2_TUNER_MODE_MONO)
+		radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
+	else
+		radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
+
+	return si470x_set_register(radio, POWERCFG);
+}
+
+
+/*
+ * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
+ */
+static int si470x_vidioc_g_frequency(struct file *file, void *priv,
+		struct v4l2_frequency *freq)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	freq->type = V4L2_TUNER_RADIO;
+	freq->frequency = si470x_get_freq(radio);
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
+ */
+static int si470x_vidioc_s_frequency(struct file *file, void *priv,
+		struct v4l2_frequency *freq)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (freq->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
+
+	return si470x_set_freq(radio, freq->frequency);
+}
+
+
+/*
+ * si470x_viddev_tamples - video device interface
+ */
+static struct video_device si470x_viddev_template = {
+	.fops			= &si470x_fops,
+	.name			= DRIVER_NAME,
+	.type			= VID_TYPE_TUNER,
+	.release		= video_device_release,
+	.vidioc_querycap	= si470x_vidioc_querycap,
+	.vidioc_g_input		= si470x_vidioc_g_input,
+	.vidioc_s_input		= si470x_vidioc_s_input,
+	.vidioc_queryctrl	= si470x_vidioc_queryctrl,
+	.vidioc_g_ctrl		= si470x_vidioc_g_ctrl,
+	.vidioc_s_ctrl		= si470x_vidioc_s_ctrl,
+	.vidioc_g_audio		= si470x_vidioc_g_audio,
+	.vidioc_s_audio		= si470x_vidioc_s_audio,
+	.vidioc_g_tuner		= si470x_vidioc_g_tuner,
+	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
+	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
+	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
+	.owner			= THIS_MODULE,
+};
+
+
+
+/**************************************************************************
+ * USB Interface
+ **************************************************************************/
+
+/*
+ * si470x_usb_driver_probe - probe for the device
+ */
+static int si470x_usb_driver_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	struct si470x_device *radio;
+
+	/* memory and interface allocations */
+	radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL);
+	if (!radio)
+		return -ENOMEM;
+	radio->videodev = video_device_alloc();
+	if (!radio->videodev) {
+		kfree(radio);
+		return -ENOMEM;
+	}
+	memcpy(radio->videodev, &si470x_viddev_template,
+			sizeof(si470x_viddev_template));
+	radio->users = 0;
+	radio->usbdev = interface_to_usbdev(intf);
+	video_set_drvdata(radio->videodev, radio);
+	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+		printk(KERN_WARNING DRIVER_NAME
+				": Could not register video device\n");
+		video_device_release(radio->videodev);
+		kfree(radio);
+		return -EIO;
+	}
+	usb_set_intfdata(intf, radio);
+
+	/* show some infos about the specific device */
+	if (si470x_get_all_registers(radio) < 0) {
+		video_device_release(radio->videodev);
+		kfree(radio);
+		return -EIO;
+	}
+	printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n",
+			radio->registers[DEVICEID], radio->registers[CHIPID]);
+
+	/* check if firmware is current */
+	if ((radio->registers[CHIPID] & CHIPID_FIRMWARE)
+			< RADIO_SW_VERSION_CURRENT)
+		printk(KERN_WARNING DRIVER_NAME
+			": This driver is known to work with chip version %d, "
+			"but the device has firmware %d.\n"
+			DRIVER_NAME
+			"If you have some trouble using this driver, please "
+			"report to V4L ML at video4linux-list@redhat.com\n",
+			radio->registers[CHIPID] & CHIPID_FIRMWARE,
+			RADIO_SW_VERSION_CURRENT);
+
+	/* set initial frequency */
+	si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
+
+	/* rds initialization */
+	radio->buf_size = rds_buf * 3;
+	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
+	if (!radio->buffer) {
+		video_device_release(radio->videodev);
+		kfree(radio);
+		return -ENOMEM;
+	}
+	radio->wr_index = 0;
+	radio->rd_index = 0;
+	init_waitqueue_head(&radio->read_queue);
+
+	/* prepare polling via eventd */
+	INIT_WORK(&radio->work, si470x_work);
+	init_timer(&radio->timer);
+	radio->timer.function = si470x_timer;
+	radio->timer.data = (unsigned long) radio;
+
+	return 0;
+}
+
+
+/*
+ * si470x_usb_driver_disconnect - disconnect the device
+ */
+static void si470x_usb_driver_disconnect(struct usb_interface *intf)
+{
+	struct si470x_device *radio = usb_get_intfdata(intf);
+
+	del_timer_sync(&radio->timer);
+	flush_scheduled_work();
+
+	usb_set_intfdata(intf, NULL);
+	if (radio) {
+		video_unregister_device(radio->videodev);
+		kfree(radio->buffer);
+		kfree(radio);
+	}
+}
+
+
+/*
+ * si470x_usb_driver - usb driver interface
+ */
+static struct usb_driver si470x_usb_driver = {
+	.name		= DRIVER_NAME,
+	.probe		= si470x_usb_driver_probe,
+	.disconnect	= si470x_usb_driver_disconnect,
+	.id_table	= si470x_usb_driver_id_table,
+};
+
+
+
+/**************************************************************************
+ * Module Interface
+ **************************************************************************/
+
+/*
+ * si470x_module_init - module init
+ */
+static int __init si470x_module_init(void)
+{
+	printk(KERN_INFO DRIVER_DESC "\n");
+	return usb_register(&si470x_usb_driver);
+}
+
+
+/*
+ * si470x_module_exit - module exit
+ */
+static void __exit si470x_module_exit(void)
+{
+	usb_deregister(&si470x_usb_driver);
+}
+
+
+module_init(si470x_module_init);
+module_exit(si470x_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION("1.0.4");

+ 42 - 10
drivers/media/video/Kconfig

@@ -45,7 +45,7 @@ comment "Audio decoders"
 
 config VIDEO_TVAUDIO
 	tristate "Simple audio decoder chips"
-	depends on VIDEO_V4L1 && I2C
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for several audio decoder chips found on some bt8xx boards:
 	  Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
@@ -57,7 +57,7 @@ config VIDEO_TVAUDIO
 
 config VIDEO_TDA7432
 	tristate "Philips TDA7432 audio processor"
-	depends on VIDEO_V4L1 && I2C
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for tda7432 audio decoder chip found on some bt8xx boards.
 
@@ -75,7 +75,7 @@ config VIDEO_TDA9840
 
 config VIDEO_TDA9875
 	tristate "Philips TDA9875 audio processor"
-	depends on VIDEO_V4L1 && I2C
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for tda9875 audio decoder chip found on some bt8xx boards.
 
@@ -109,9 +109,19 @@ config VIDEO_MSP3400
 	  To compile this driver as a module, choose M here: the
 	  module will be called msp3400.
 
+config VIDEO_CS5345
+	tristate "Cirrus Logic CS5345 audio ADC"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Cirrus Logic CS5345 24-bit, 192 kHz
+	  stereo A/D converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cs5345.
+
 config VIDEO_CS53L32A
 	tristate "Cirrus Logic CS53L32A audio ADC"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Cirrus Logic CS53L32A low voltage
 	  stereo A/D converter.
@@ -119,6 +129,15 @@ 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 && EXPERIMENTAL
+       ---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
@@ -130,7 +149,7 @@ config VIDEO_TLV320AIC23B
 
 config VIDEO_WM8775
 	tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Wolfson Microelectronics WM8775 high
 	  performance stereo A/D Converter with a 4 channel input mixer.
@@ -140,7 +159,7 @@ config VIDEO_WM8775
 
 config VIDEO_WM8739
 	tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Wolfson Microelectronics WM8739
 	  stereo A/D Converter.
@@ -244,7 +263,7 @@ config VIDEO_SAA7114
 
 config VIDEO_SAA711X
 	tristate "Philips SAA7113/4/5 video decoders"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Philips SAA7113/4/5 video decoders.
 
@@ -300,7 +319,7 @@ comment "Video encoders"
 
 config VIDEO_SAA7127
 	tristate "Philips SAA7127/9 digital video encoders"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Philips SAA7127/9 digital video encoders.
 
@@ -338,7 +357,7 @@ comment "Video improvement chips"
 
 config VIDEO_UPD64031A
 	tristate "NEC Electronics uPD64031A Ghost Reduction"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the NEC Electronics uPD64031A Ghost Reduction
 	  video chip. It is most often found in NTSC TV cards made for
@@ -350,7 +369,7 @@ config VIDEO_UPD64031A
 
 config VIDEO_UPD64083
 	tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the NEC Electronics uPD64083 3-Dimensional Y/C
 	  separation video chip. It is used to improve the quality of
@@ -802,6 +821,19 @@ config USB_ZR364XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called zr364xx.
 
+config USB_STKWEBCAM
+	tristate "USB Syntek DC1125 Camera support"
+	depends on VIDEO_V4L2 && EXPERIMENTAL
+	---help---
+	  Say Y here if you want to use this type of camera.
+	  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://stk11xx.sourceforge.net
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called stkwebcam.
+
 endif # V4L_USB_DRIVERS
 
 endif # VIDEO_CAPTURE_DRIVERS

+ 9 - 1
drivers/media/video/Makefile

@@ -4,10 +4,12 @@
 
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
-tuner-objs	:=	tuner-core.o tuner-types.o tda9887.o
+tuner-objs	:=	tuner-core.o tuner-types.o
 
 msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
 
+stkwebcam-objs	:=	stk-webcam.o stk-sensor.o
+
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
 			   v4l2-int-device.o
 
@@ -66,7 +68,9 @@ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
 obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_M52790) += m52790.o
 obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
 obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
 obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
@@ -81,11 +85,13 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 
+obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
 obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
 obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
 obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
 obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
 obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
+obj-$(CONFIG_TUNER_TDA9887) += tda9887.o
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -112,6 +118,7 @@ obj-$(CONFIG_USB_SE401)         += se401.o
 obj-$(CONFIG_USB_STV680)        += stv680.o
 obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
 obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
+obj-$(CONFIG_USB_STKWEBCAM)     += stkwebcam.o
 
 obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
@@ -129,3 +136,4 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends

+ 1 - 1
drivers/media/video/bt8xx/Kconfig

@@ -1,6 +1,6 @@
 config VIDEO_BT848
 	tristate "BT848 Video For Linux"
-	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1
+	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
 	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_BTCX

+ 1 - 1
drivers/media/video/bt8xx/Makefile

@@ -4,7 +4,7 @@
 
 bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
 		       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
-		       bttv-input.o
+		       bttv-input.o bttv-audio-hook.o
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o
 

+ 382 - 0
drivers/media/video/bt8xx/bttv-audio-hook.c

@@ -0,0 +1,382 @@
+/*
+ * Handlers for board audio hooks, splitted from bttv-cards
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include "bttv-audio-hook.h"
+
+#include <linux/delay.h>
+
+/* ----------------------------------------------------------------------- */
+/* winview                                                                 */
+
+void winview_volume(struct bttv *btv, __u16 volume)
+{
+	/* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
+	int bits_out, loops, vol, data;
+
+	/* 32 levels logarithmic */
+	vol = 32 - ((volume>>11));
+	/* units */
+	bits_out = (PT2254_DBS_IN_2>>(vol%5));
+	/* tens */
+	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
+	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
+	data = gpio_read();
+	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
+		  WINVIEW_PT2254_STROBE);
+	for (loops = 17; loops >= 0 ; loops--) {
+		if (bits_out & (1<<loops))
+			data |=  WINVIEW_PT2254_DATA;
+		else
+			data &= ~WINVIEW_PT2254_DATA;
+		gpio_write(data);
+		udelay(5);
+		data |= WINVIEW_PT2254_CLK;
+		gpio_write(data);
+		udelay(5);
+		data &= ~WINVIEW_PT2254_CLK;
+		gpio_write(data);
+	}
+	data |=  WINVIEW_PT2254_STROBE;
+	data &= ~WINVIEW_PT2254_DATA;
+	gpio_write(data);
+	udelay(10);
+	data &= ~WINVIEW_PT2254_STROBE;
+	gpio_write(data);
+}
+
+/* ----------------------------------------------------------------------- */
+/* mono/stereo control for various cards (which don't use i2c chips but    */
+/* connect something to the GPIO pins                                      */
+
+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int con = 0;
+
+	if (set) {
+		gpio_inout(0x300, 0x300);
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
+			con = 0x000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			con = 0x300;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			con = 0x200;
+/*		if (t->audmode & V4L2_TUNER_MODE_MONO)
+ *			con = 0x100; */
+		gpio_bits(0x300, con);
+	} else {
+		t->audmode = V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int val, con;
+
+	if (btv->radio_user)
+		return;
+
+	val = gpio_read();
+	if (set) {
+		con = 0x000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2) {
+			if (t->audmode & V4L2_TUNER_MODE_LANG1) {
+				/* LANG1 + LANG2 */
+				con = 0x100;
+			}
+			else {
+				/* LANG2 */
+				con = 0x300;
+			}
+		}
+		if (con != (val & 0x300)) {
+			gpio_bits(0x300, con);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"gvbctv5pci");
+		}
+	} else {
+		switch (val & 0x70) {
+		  case 0x10:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG1 |  V4L2_TUNER_SUB_LANG2;
+			break;
+		  case 0x30:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG2;
+			break;
+		  case 0x50:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG1;
+			break;
+		  case 0x60:
+			t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			break;
+		  case 0x70:
+			t->rxsubchans = V4L2_TUNER_SUB_MONO;
+			break;
+		  default:
+			t->rxsubchans = V4L2_TUNER_SUB_MONO |
+					 V4L2_TUNER_SUB_STEREO |
+					 V4L2_TUNER_SUB_LANG1 |
+					 V4L2_TUNER_SUB_LANG2;
+		}
+		t->audmode = V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
+ *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
+ *  0xdde enables mono and 0xccd enables sap
+ *
+ * Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
+ *  input/output sound connection, so both must be set for output mode.
+ *
+ * Looks like it's needed only for the "tvphone", the "tvphone 98"
+ * handles this with a tda9840
+ *
+ */
+
+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	int val = 0;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
+			val = 0x02;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			val = 0x01;
+		if (val) {
+			gpio_bits(0x03,val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"avermedia");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1;
+		return;
+	}
+}
+
+
+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	int val = 0;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
+			val = 0x01;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)  /* STEREO */
+			val = 0x02;
+		btaor(val, ~0x03, BT848_GPIO_DATA);
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"avermedia");
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		return;
+	}
+}
+
+/* Lifetec 9415 handling */
+
+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	int val = 0;
+
+	if (gpio_read() & 0x4000) {
+		t->audmode = V4L2_TUNER_MODE_MONO;
+		return;
+	}
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)  /* A2 SAP */
+			val = 0x0080;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */
+			val = 0x0880;
+		if ((t->audmode & V4L2_TUNER_MODE_LANG1) ||
+		    (t->audmode & V4L2_TUNER_MODE_MONO))
+			val = 0;
+		gpio_bits(0x0880, val);
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"lt9415");
+	} else {
+		/* autodetect doesn't work with this card :-( */
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		return;
+	}
+}
+
+/* TDA9821 on TerraTV+ Bt848, Bt878 */
+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *t, int set)
+{
+	unsigned int con = 0;
+
+	if (set) {
+		gpio_inout(0x180000,0x180000);
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			con = 0x080000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			con = 0x180000;
+		gpio_bits(0x180000, con);
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"terratv");
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+
+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned long val = 0;
+
+	if (set) {
+		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
+		if (t->audmode & V4L2_TUNER_MODE_MONO)		/* Mono */
+			val = 0x420000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)	/* Mono */
+			val = 0x420000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)	/* SAP */
+			val = 0x410000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)	/* Stereo */
+			val = 0x020000;
+		if (val) {
+			gpio_bits(0x430000, val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"winfast2000");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
+ * revision 9B has on-board TDA9874A sound decoder).
+ *
+ * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
+ *       will mute this cards.
+ */
+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int val = 0;
+
+	if (btv->radio_user)
+		return;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
+			val = 0x01;
+		}
+		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
+		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
+			val = 0x02;
+		}
+		if (val) {
+			gpio_bits(0x03,val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"pvbt878p9b");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for FlyVideo 2000S (with tda9874 decoder)
+ * based on pvbt878p9b_audio() - this is not tested, please fix!!!
+ */
+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int val = 0xffff;
+
+	if (btv->radio_user)
+		return;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
+			val = 0x0000;
+		}
+		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
+		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
+			val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
+		}
+		if (val != 0xffff) {
+			gpio_bits(0x1800, val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"fv2000s");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * sound control for Canopus WinDVR PCI
+ * Masaki Suzuki <masaki@btree.org>
+ */
+void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned long val = 0;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_MONO)
+			val = 0x040000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
+			val = 0;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			val = 0x100000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			val = 0;
+		if (val) {
+			gpio_bits(0x140000, val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"windvr");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * sound control for AD-TVK503
+ * Hiroshi Takekawa <sian@big.or.jp>
+ */
+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int con = 0xffffff;
+
+	/* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
+
+	if (set) {
+		/* btor(***, BT848_GPIO_OUT_EN); */
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
+			con = 0x00000000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			con = 0x00180000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			con = 0x00000000;
+		if (t->audmode & V4L2_TUNER_MODE_MONO)
+			con = 0x00060000;
+		if (con != 0xffffff) {
+			gpio_bits(0x1e0000,con);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv, "adtvk503");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+	}
+}

+ 23 - 0
drivers/media/video/bt8xx/bttv-audio-hook.h

@@ -0,0 +1,23 @@
+/*
+ * Handlers for board audio hooks, splitted from bttv-cards
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include "bttvp.h"
+
+void winview_volume (struct bttv *btv, __u16 volume);
+
+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *tuner, int set);
+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+

+ 28 - 416
drivers/media/video/bt8xx/bttv-cards.c

@@ -39,6 +39,7 @@
 #include "bttvp.h"
 #include <media/v4l2-common.h>
 #include <media/tvaudio.h>
+#include "bttv-audio-hook.h"
 
 /* fwd decl */
 static void boot_msp34xx(struct bttv *btv, int pin);
@@ -50,20 +51,6 @@ static void modtec_eeprom(struct bttv *btv);
 static void init_PXC200(struct bttv *btv);
 static void init_RTV24(struct bttv *btv);
 
-static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
-static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
-static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
-				    int set);
-static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v,
-				      int set);
-static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
-static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
-static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set);
-static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
-static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
-static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
-static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
-static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
 static void rv605_muxsel(struct bttv *btv, unsigned int input);
 static void eagle_muxsel(struct bttv *btv, unsigned int input);
 static void xguard_muxsel(struct bttv *btv, unsigned int input);
@@ -427,7 +414,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= avermedia_tvphone_audio,
+		.audio_mode_gpio= avermedia_tvphone_audio,
 		.has_remote     = 1,
 	},
 	[BTTV_BOARD_MATRIX_VISION] = {
@@ -539,7 +526,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = avermedia_tv_stereo_audio,
+		.audio_mode_gpio= avermedia_tv_stereo_audio,
 		.no_gpioirq     = 1,
 	},
 	[BTTV_BOARD_VHX] = {
@@ -604,7 +591,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= winview_audio,
+		.volume_gpio	= winview_volume,
 		.has_radio	= 1,
 	},
 	[BTTV_BOARD_AVEC_INTERCAP] = {
@@ -728,7 +715,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = terratv_audio,
+		.audio_mode_gpio= terratv_audio,
 	},
 	[BTTV_BOARD_HAUPPAUG_WCAM] = {
 		.name		= "Hauppauge WinCam newer (bt878)",
@@ -776,7 +763,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= terratv_audio,
+		.audio_mode_gpio= terratv_audio,
 		/* GPIO wiring:
 		External 20 pin connector (for Active Radio Upgrade board)
 		gpio00: i2c-sda
@@ -915,7 +902,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= winfast2000_audio,
+		.audio_mode_gpio= winfast2000_audio,
 		.has_remote     = 1,
 	},
 	[BTTV_BOARD_CHRONOS_VS2] = {
@@ -1035,7 +1022,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_radio	= 1,
-		.audio_hook	= avermedia_tvphone_audio,
+		.audio_mode_gpio= avermedia_tvphone_audio,
 	},
 	[BTTV_BOARD_PV951] = {
 		.name		= "ProVideo PV951", /* pic16c54 */
@@ -1167,7 +1154,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_ALPS_TSHC6_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= gvbctv3pci_audio,
+		.audio_mode_gpio= gvbctv3pci_audio,
 	},
 	[BTTV_BOARD_PXELVWPLTVPAK] = {
 		.name		= "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
@@ -1472,7 +1459,7 @@ struct tvcard bttv_tvcards[] = {
 				/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
 		.gpiomux 	= { 0x0000,0x0800,0x1000,0x1000 },
 		.gpiomute 	= 0x1800,
-		.audio_hook	= fv2000s_audio,
+		.audio_mode_gpio= fv2000s_audio,
 		.no_msp34xx	= 1,
 		.no_tda9875	= 1,
 		.needs_tvaudio  = 1,
@@ -1513,7 +1500,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = gvbctv3pci_audio,
+		.audio_mode_gpio= gvbctv3pci_audio,
 	},
 
 	/* ---- card 0x44 ---------------------------------- */
@@ -1632,7 +1619,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= pvbt878p9b_audio, /* Note: not all cards have stereo */
+		.audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */
 		.has_radio	= 1,  /* Note: not all cards have radio */
 		.has_remote     = 1,
 		/* GPIO wiring:
@@ -1710,7 +1697,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_PHILIPS_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = windvr_audio,
+		.audio_mode_gpio= windvr_audio,
 	},
 	[BTTV_BOARD_GRANDTEC_MULTI] = {
 		.name           = "GrandTec Multi Capture Card (Bt878)",
@@ -1807,7 +1794,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_PHILIPS_NTSC_M,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = gvbctv5pci_audio,
+		.audio_mode_gpio= gvbctv5pci_audio,
 		.has_radio      = 1,
 	},
 	[BTTV_BOARD_OSPREY1x0] = {
@@ -2106,7 +2093,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_PHILIPS_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= adtvk503_audio,
+		.audio_mode_gpio= adtvk503_audio,
 	},
 
 		/* ---- card 0x64 ---------------------------------- */
@@ -3173,8 +3160,8 @@ static void flyvideo_gpio(struct bttv *btv)
 	/* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
 	 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
 	 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
-	if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
-	/* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */
+	if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio;
+	/* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
 }
 
 static int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
@@ -3574,8 +3561,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
 	}
 
 	if (btv->tda9887_conf) {
-		bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
-							&btv->tda9887_conf);
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &btv->tda9887_conf;
+
+		bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg);
 	}
 
 	btv->svhs = bttv_tvcards[btv->c.type].svhs;
@@ -3590,8 +3581,10 @@ void __devinit bttv_init_card2(struct bttv *btv)
 		btv->has_remote=1;
 	if (!bttv_tvcards[btv->c.type].no_gpioirq)
 		btv->gpioirq=1;
-	if (bttv_tvcards[btv->c.type].audio_hook)
-		btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
+	if (bttv_tvcards[btv->c.type].volume_gpio)
+		btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio;
+	if (bttv_tvcards[btv->c.type].audio_mode_gpio)
+		btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
 
 	if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
 		/* detect Bt832 chip for quartzsight digital camera */
@@ -3950,7 +3943,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
 void bttv_tda9880_setnorm(struct bttv *btv, int norm)
 {
 	/* fix up our card entry */
-	if(norm==VIDEO_MODE_NTSC) {
+	if(norm==V4L2_STD_NTSC) {
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
@@ -4319,387 +4312,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
 	tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
 }
 
-
-/* ----------------------------------------------------------------------- */
-/* winview                                                                 */
-
-static void winview_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	/* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
-	int bits_out, loops, vol, data;
-
-	if (!set) {
-		/* Fixed by Leandro Lucarella <luca@linuxmendoza.org.ar (07/31/01) */
-		v->flags |= VIDEO_AUDIO_VOLUME;
-		return;
-	}
-
-	/* 32 levels logarithmic */
-	vol = 32 - ((v->volume>>11));
-	/* units */
-	bits_out = (PT2254_DBS_IN_2>>(vol%5));
-	/* tens */
-	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
-	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
-	data = gpio_read();
-	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
-		  WINVIEW_PT2254_STROBE);
-	for (loops = 17; loops >= 0 ; loops--) {
-		if (bits_out & (1<<loops))
-			data |=  WINVIEW_PT2254_DATA;
-		else
-			data &= ~WINVIEW_PT2254_DATA;
-		gpio_write(data);
-		udelay(5);
-		data |= WINVIEW_PT2254_CLK;
-		gpio_write(data);
-		udelay(5);
-		data &= ~WINVIEW_PT2254_CLK;
-		gpio_write(data);
-	}
-	data |=  WINVIEW_PT2254_STROBE;
-	data &= ~WINVIEW_PT2254_DATA;
-	gpio_write(data);
-	udelay(10);
-	data &= ~WINVIEW_PT2254_STROBE;
-	gpio_write(data);
-}
-
-/* ----------------------------------------------------------------------- */
-/* mono/stereo control for various cards (which don't use i2c chips but    */
-/* connect something to the GPIO pins                                      */
-
-static void
-gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int con = 0;
-
-	if (set) {
-		gpio_inout(0x300, 0x300);
-		if (v->mode & VIDEO_SOUND_LANG1)
-			con = 0x000;
-		if (v->mode & VIDEO_SOUND_LANG2)
-			con = 0x300;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			con = 0x200;
-/*		if (v->mode & VIDEO_SOUND_MONO)
- *			con = 0x100; */
-		gpio_bits(0x300, con);
-	} else {
-		v->mode = VIDEO_SOUND_STEREO |
-			  VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
-	}
-}
-
-static void
-gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int val, con;
-
-	if (btv->radio_user)
-		return;
-
-	val = gpio_read();
-	if (set) {
-		con = 0x000;
-		if (v->mode & VIDEO_SOUND_LANG2) {
-			if (v->mode & VIDEO_SOUND_LANG1) {
-				/* LANG1 + LANG2 */
-				con = 0x100;
-			}
-			else {
-				/* LANG2 */
-				con = 0x300;
-			}
-		}
-		if (con != (val & 0x300)) {
-			gpio_bits(0x300, con);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"gvbctv5pci");
-		}
-	} else {
-		switch (val & 0x70) {
-		  case 0x10:
-			v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-			break;
-		  case 0x30:
-			v->mode = VIDEO_SOUND_LANG2;
-			break;
-		  case 0x50:
-			v->mode = VIDEO_SOUND_LANG1;
-			break;
-		  case 0x60:
-			v->mode = VIDEO_SOUND_STEREO;
-			break;
-		  case 0x70:
-			v->mode = VIDEO_SOUND_MONO;
-			break;
-		  default:
-			v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-				  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-		}
-	}
-}
-
-/*
- * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
- *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
- *  0xdde enables mono and 0xccd enables sap
- *
- * Petr Vandrovec <VANDROVE@vc.cvut.cz>
- *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
- *  input/output sound connection, so both must be set for output mode.
- *
- * Looks like it's needed only for the "tvphone", the "tvphone 98"
- * handles this with a tda9840
- *
- */
-static void
-avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	int val = 0;
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
-			val = 0x02;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			val = 0x01;
-		if (val) {
-			gpio_bits(0x03,val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"avermedia");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1;
-		return;
-	}
-}
-
-static void
-avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	int val = 0;
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
-			val = 0x01;
-		if (v->mode & VIDEO_SOUND_STEREO)  /* STEREO */
-			val = 0x02;
-		btaor(val, ~0x03, BT848_GPIO_DATA);
-		if (bttv_gpio)
-			bttv_gpio_tracking(btv,"avermedia");
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-		return;
-	}
-}
-
-/* Lifetec 9415 handling */
-static void
-lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	int val = 0;
-
-	if (gpio_read() & 0x4000) {
-		v->mode = VIDEO_SOUND_MONO;
-		return;
-	}
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
-			val = 0x0080;
-		if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
-			val = 0x0880;
-		if ((v->mode & VIDEO_SOUND_LANG1) ||
-		    (v->mode & VIDEO_SOUND_MONO))
-			val = 0;
-		gpio_bits(0x0880, val);
-		if (bttv_gpio)
-			bttv_gpio_tracking(btv,"lt9415");
-	} else {
-		/* autodetect doesn't work with this card :-( */
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-		return;
-	}
-}
-
-/* TDA9821 on TerraTV+ Bt848, Bt878 */
-static void
-terratv_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int con = 0;
-
-	if (set) {
-		gpio_inout(0x180000,0x180000);
-		if (v->mode & VIDEO_SOUND_LANG2)
-			con = 0x080000;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			con = 0x180000;
-		gpio_bits(0x180000, con);
-		if (bttv_gpio)
-			bttv_gpio_tracking(btv,"terratv");
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-static void
-winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned long val = 0;
-
-	if (set) {
-		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
-		if (v->mode & VIDEO_SOUND_MONO)		/* Mono */
-			val = 0x420000;
-		if (v->mode & VIDEO_SOUND_LANG1)	/* Mono */
-			val = 0x420000;
-		if (v->mode & VIDEO_SOUND_LANG2)	/* SAP */
-			val = 0x410000;
-		if (v->mode & VIDEO_SOUND_STEREO)	/* Stereo */
-			val = 0x020000;
-		if (val) {
-			gpio_bits(0x430000, val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"winfast2000");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-/*
- * Dariusz Kowalewski <darekk@automex.pl>
- * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
- * revision 9B has on-board TDA9874A sound decoder).
- *
- * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
- *       will mute this cards.
- */
-static void
-pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int val = 0;
-
-	if (btv->radio_user)
-		return;
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_MONO)	{
-			val = 0x01;
-		}
-		if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
-		    || (v->mode & VIDEO_SOUND_STEREO)) {
-			val = 0x02;
-		}
-		if (val) {
-			gpio_bits(0x03,val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"pvbt878p9b");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-/*
- * Dariusz Kowalewski <darekk@automex.pl>
- * sound control for FlyVideo 2000S (with tda9874 decoder)
- * based on pvbt878p9b_audio() - this is not tested, please fix!!!
- */
-static void
-fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int val = 0xffff;
-
-	if (btv->radio_user)
-		return;
-	if (set) {
-		if (v->mode & VIDEO_SOUND_MONO)	{
-			val = 0x0000;
-		}
-		if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
-		    || (v->mode & VIDEO_SOUND_STEREO)) {
-			val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
-		}
-		if (val != 0xffff) {
-			gpio_bits(0x1800, val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"fv2000s");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-/*
- * sound control for Canopus WinDVR PCI
- * Masaki Suzuki <masaki@btree.org>
- */
-static void
-windvr_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned long val = 0;
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_MONO)
-			val = 0x040000;
-		if (v->mode & VIDEO_SOUND_LANG1)
-			val = 0;
-		if (v->mode & VIDEO_SOUND_LANG2)
-			val = 0x100000;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			val = 0;
-		if (val) {
-			gpio_bits(0x140000, val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"windvr");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-/*
- * sound control for AD-TVK503
- * Hiroshi Takekawa <sian@big.or.jp>
- */
-static void
-adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int con = 0xffffff;
-
-	/* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
-
-	if (set) {
-		/* btor(***, BT848_GPIO_OUT_EN); */
-		if (v->mode & VIDEO_SOUND_LANG1)
-			con = 0x00000000;
-		if (v->mode & VIDEO_SOUND_LANG2)
-			con = 0x00180000;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			con = 0x00000000;
-		if (v->mode & VIDEO_SOUND_MONO)
-			con = 0x00060000;
-		if (con != 0xffffff) {
-			gpio_bits(0x1e0000,con);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv, "adtvk503");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			  VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
-	}
-}
-
 /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
  *
  * This is needed because rv605 don't use a normal multiplex, but a crosspoint

File diff suppressed because it is too large
+ 268 - 480
drivers/media/video/bt8xx/bttv-driver.c


+ 5 - 0
drivers/media/video/bt8xx/bttv-input.c

@@ -69,6 +69,11 @@ static void ir_handle_key(struct bttv *btv)
 	    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
 		ir_input_keydown(ir->dev,&ir->ir,data,data);
 	} else {
+		/* HACK: Probably, ir->mask_keydown is missing
+		   for this board */
+		if (btv->c.type == BTTV_BOARD_WINFAST2000)
+			ir_input_keydown(ir->dev, &ir->ir, data, data);
+
 		ir_input_nokey(ir->dev,&ir->ir);
 	}
 

+ 7 - 7
drivers/media/video/bt8xx/bttv-risc.c

@@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
 	videobuf_dma_free(dma);
 	btcx_riscmem_free(btv->c.pci,&buf->bottom);
 	btcx_riscmem_free(btv->c.pci,&buf->top);
-	buf->vb.state = STATE_NEEDS_INIT;
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 int
@@ -602,7 +602,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
 	if (vbi) {
 		unsigned int crop, vdelay;
 
-		vbi->vb.state = STATE_ACTIVE;
+		vbi->vb.state = VIDEOBUF_ACTIVE;
 		list_del(&vbi->vb.queue);
 
 		/* VDELAY is start of video, end of VBI capturing. */
@@ -644,12 +644,12 @@ bttv_buffer_activate_video(struct bttv *btv,
 	/* video capture */
 	if (NULL != set->top  &&  NULL != set->bottom) {
 		if (set->top == set->bottom) {
-			set->top->vb.state    = STATE_ACTIVE;
+			set->top->vb.state    = VIDEOBUF_ACTIVE;
 			if (set->top->vb.queue.next)
 				list_del(&set->top->vb.queue);
 		} else {
-			set->top->vb.state    = STATE_ACTIVE;
-			set->bottom->vb.state = STATE_ACTIVE;
+			set->top->vb.state    = VIDEOBUF_ACTIVE;
+			set->bottom->vb.state = VIDEOBUF_ACTIVE;
 			if (set->top->vb.queue.next)
 				list_del(&set->top->vb.queue);
 			if (set->bottom->vb.queue.next)
@@ -666,7 +666,7 @@ bttv_buffer_activate_video(struct bttv *btv,
 		btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
 		      ~0x0f, BT848_COLOR_CTL);
 	} else if (NULL != set->top) {
-		set->top->vb.state  = STATE_ACTIVE;
+		set->top->vb.state  = VIDEOBUF_ACTIVE;
 		if (set->top->vb.queue.next)
 			list_del(&set->top->vb.queue);
 		bttv_apply_geo(btv, &set->top->geo,1);
@@ -677,7 +677,7 @@ bttv_buffer_activate_video(struct bttv *btv,
 		btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
 		btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
 	} else if (NULL != set->bottom) {
-		set->bottom->vb.state = STATE_ACTIVE;
+		set->bottom->vb.state = VIDEOBUF_ACTIVE;
 		if (set->bottom->vb.queue.next)
 			list_del(&set->bottom->vb.queue);
 		bttv_apply_geo(btv, &set->bottom->geo,1);

+ 28 - 30
drivers/media/video/bt8xx/bttv-vbi.c

@@ -142,7 +142,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
 		redo_dma_risc = 1;
 	}
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		redo_dma_risc = 1;
 		if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
 			goto fail;
@@ -189,7 +189,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
 	/* For bttv_buffer_activate_vbi(). */
 	buf->geo.vdelay = min_vdelay;
 
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->vb.field = field;
 	dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
 		vb, &buf->top, &buf->bottom,
@@ -209,7 +209,7 @@ vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
 
 	dprintk("queue %p\n",vb);
-	buf->vb.state = STATE_QUEUED;
+	buf->vb.state = VIDEOBUF_QUEUED;
 	list_add_tail(&buf->vb.queue,&btv->vcapture);
 	if (NULL == btv->cvbi) {
 		fh->btv->loop_irq |= 4;
@@ -236,10 +236,8 @@ struct videobuf_queue_ops bttv_vbi_qops = {
 
 /* ----------------------------------------------------------------------- */
 
-static int
-try_fmt			(struct v4l2_vbi_format *	f,
-			 const struct bttv_tvnorm *	tvnorm,
-			 __s32				crop_start)
+static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
+			__s32 crop_start)
 {
 	__s32 min_start, max_start, max_end, f2_offset;
 	unsigned int i;
@@ -305,10 +303,9 @@ try_fmt			(struct v4l2_vbi_format *	f,
 	return 0;
 }
 
-int
-bttv_vbi_try_fmt	(struct bttv_fh *		fh,
-			 struct v4l2_vbi_format *	f)
+int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 {
+	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 	const struct bttv_tvnorm *tvnorm;
 	__s32 crop_start;
@@ -320,13 +317,13 @@ bttv_vbi_try_fmt	(struct bttv_fh *		fh,
 
 	mutex_unlock(&btv->lock);
 
-	return try_fmt(f, tvnorm, crop_start);
+	return try_fmt(&frt->fmt.vbi, tvnorm, crop_start);
 }
 
-int
-bttv_vbi_set_fmt	(struct bttv_fh *		fh,
-			 struct v4l2_vbi_format *	f)
+
+int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 {
+	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 	const struct bttv_tvnorm *tvnorm;
 	__s32 start1, end;
@@ -340,11 +337,12 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
 
 	tvnorm = &bttv_tvnorms[btv->tvnorm];
 
-	rc = try_fmt(f, tvnorm, btv->crop_start);
+	rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start);
 	if (0 != rc)
 		goto fail;
 
-	start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
+	start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] +
+		tvnorm->vbistart[0];
 
 	/* First possible line of video capturing. Should be
 	   max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
@@ -352,11 +350,11 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
 	   pretend the VBI and video capture window may overlap,
 	   so end = start + 1, the lowest possible value, times two
 	   because vbi_fmt.end counts field lines times two. */
-	end = max(f->start[0], start1) * 2 + 2;
+	end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
 
 	mutex_lock(&fh->vbi.lock);
 
-	fh->vbi_fmt.fmt    = *f;
+	fh->vbi_fmt.fmt    = frt->fmt.vbi;
 	fh->vbi_fmt.tvnorm = tvnorm;
 	fh->vbi_fmt.end    = end;
 
@@ -370,13 +368,13 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
 	return rc;
 }
 
-void
-bttv_vbi_get_fmt	(struct bttv_fh *		fh,
-			 struct v4l2_vbi_format *	f)
+
+int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 {
+	struct bttv_fh *fh = f;
 	const struct bttv_tvnorm *tvnorm;
 
-	*f = fh->vbi_fmt.fmt;
+	frt->fmt.vbi = fh->vbi_fmt.fmt;
 
 	tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
 
@@ -391,28 +389,28 @@ bttv_vbi_get_fmt	(struct bttv_fh *		fh,
 		max_end = (tvnorm->cropcap.bounds.top
 			   + tvnorm->cropcap.bounds.height) >> 1;
 
-		f->sampling_rate = tvnorm->Fsc;
+		frt->fmt.vbi.sampling_rate = tvnorm->Fsc;
 
 		for (i = 0; i < 2; ++i) {
 			__s32 new_start;
 
-			new_start = f->start[i]
+			new_start = frt->fmt.vbi.start[i]
 				+ tvnorm->vbistart[i]
 				- fh->vbi_fmt.tvnorm->vbistart[i];
 
-			f->start[i] = min(new_start, max_end - 1);
-			f->count[i] = min((__s32) f->count[i],
-					  max_end - f->start[i]);
+			frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
+			frt->fmt.vbi.count[i] =
+				min((__s32) frt->fmt.vbi.count[i],
+					  max_end - frt->fmt.vbi.start[i]);
 
 			max_end += tvnorm->vbistart[1]
 				- tvnorm->vbistart[0];
 		}
 	}
+	return 0;
 }
 
-void
-bttv_vbi_fmt_reset	(struct bttv_vbi_fmt *		f,
-			 int				norm)
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm)
 {
 	const struct bttv_tvnorm *tvnorm;
 	unsigned int real_samples_per_line;

Some files were not shown because too many files changed in this diff