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 năm trước cách đây
mục cha
commit
b31fde6db2
100 tập tin đã thay đổi với 10542 bổ sung2430 xóa
  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. 1018 1406
      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

+ 1018 - 1406
drivers/media/video/bt8xx/bttv-driver.c

@@ -9,6 +9,12 @@
     some v4l2 code lines are taken from Justin's bttv2 driver which is
     (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
 
+    V4L1 removal from:
+    (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+
+    Fixes to be fully V4L2 compliant by
+    (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+
     Cropping and overscan support
     Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
     Sponsored by OPQ Systems AB
@@ -157,7 +163,7 @@ MODULE_LICENSE("GPL");
 static ssize_t show_card(struct device *cd,
 			 struct device_attribute *attr, char *buf)
 {
-	struct video_device *vfd = to_video_device(cd);
+	struct video_device *vfd = container_of(cd, struct video_device, class_dev);
 	struct bttv *btv = dev_get_drvdata(vfd->dev);
 	return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
 }
@@ -470,31 +476,27 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
 /* ----------------------------------------------------------------------- */
 /* bttv format list
    packed pixel formats must come first */
-static const struct bttv_format bttv_formats[] = {
+static const struct bttv_format formats[] = {
 	{
 		.name     = "8 bpp, gray",
-		.palette  = VIDEO_PALETTE_GREY,
 		.fourcc   = V4L2_PIX_FMT_GREY,
 		.btformat = BT848_COLOR_FMT_Y8,
 		.depth    = 8,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "8 bpp, dithered color",
-		.palette  = VIDEO_PALETTE_HI240,
 		.fourcc   = V4L2_PIX_FMT_HI240,
 		.btformat = BT848_COLOR_FMT_RGB8,
 		.depth    = 8,
 		.flags    = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
 	},{
 		.name     = "15 bpp RGB, le",
-		.palette  = VIDEO_PALETTE_RGB555,
 		.fourcc   = V4L2_PIX_FMT_RGB555,
 		.btformat = BT848_COLOR_FMT_RGB15,
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "15 bpp RGB, be",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_RGB555X,
 		.btformat = BT848_COLOR_FMT_RGB15,
 		.btswap   = 0x03, /* byteswap */
@@ -502,14 +504,12 @@ static const struct bttv_format bttv_formats[] = {
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "16 bpp RGB, le",
-		.palette  = VIDEO_PALETTE_RGB565,
 		.fourcc   = V4L2_PIX_FMT_RGB565,
 		.btformat = BT848_COLOR_FMT_RGB16,
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "16 bpp RGB, be",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_RGB565X,
 		.btformat = BT848_COLOR_FMT_RGB16,
 		.btswap   = 0x03, /* byteswap */
@@ -517,21 +517,18 @@ static const struct bttv_format bttv_formats[] = {
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "24 bpp RGB, le",
-		.palette  = VIDEO_PALETTE_RGB24,
 		.fourcc   = V4L2_PIX_FMT_BGR24,
 		.btformat = BT848_COLOR_FMT_RGB24,
 		.depth    = 24,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "32 bpp RGB, le",
-		.palette  = VIDEO_PALETTE_RGB32,
 		.fourcc   = V4L2_PIX_FMT_BGR32,
 		.btformat = BT848_COLOR_FMT_RGB32,
 		.depth    = 32,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "32 bpp RGB, be",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_RGB32,
 		.btformat = BT848_COLOR_FMT_RGB32,
 		.btswap   = 0x0f, /* byte+word swap */
@@ -539,21 +536,18 @@ static const struct bttv_format bttv_formats[] = {
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "4:2:2, packed, YUYV",
-		.palette  = VIDEO_PALETTE_YUV422,
 		.fourcc   = V4L2_PIX_FMT_YUYV,
 		.btformat = BT848_COLOR_FMT_YUY2,
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "4:2:2, packed, YUYV",
-		.palette  = VIDEO_PALETTE_YUYV,
 		.fourcc   = V4L2_PIX_FMT_YUYV,
 		.btformat = BT848_COLOR_FMT_YUY2,
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "4:2:2, packed, UYVY",
-		.palette  = VIDEO_PALETTE_UYVY,
 		.fourcc   = V4L2_PIX_FMT_UYVY,
 		.btformat = BT848_COLOR_FMT_YUY2,
 		.btswap   = 0x03, /* byteswap */
@@ -561,7 +555,6 @@ static const struct bttv_format bttv_formats[] = {
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "4:2:2, planar, Y-Cb-Cr",
-		.palette  = VIDEO_PALETTE_YUV422P,
 		.fourcc   = V4L2_PIX_FMT_YUV422P,
 		.btformat = BT848_COLOR_FMT_YCrCb422,
 		.depth    = 16,
@@ -570,7 +563,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 0,
 	},{
 		.name     = "4:2:0, planar, Y-Cb-Cr",
-		.palette  = VIDEO_PALETTE_YUV420P,
 		.fourcc   = V4L2_PIX_FMT_YUV420,
 		.btformat = BT848_COLOR_FMT_YCrCb422,
 		.depth    = 12,
@@ -579,7 +571,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 1,
 	},{
 		.name     = "4:2:0, planar, Y-Cr-Cb",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_YVU420,
 		.btformat = BT848_COLOR_FMT_YCrCb422,
 		.depth    = 12,
@@ -588,7 +579,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 1,
 	},{
 		.name     = "4:1:1, planar, Y-Cb-Cr",
-		.palette  = VIDEO_PALETTE_YUV411P,
 		.fourcc   = V4L2_PIX_FMT_YUV411P,
 		.btformat = BT848_COLOR_FMT_YCrCb411,
 		.depth    = 12,
@@ -597,7 +587,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 0,
 	},{
 		.name     = "4:1:0, planar, Y-Cb-Cr",
-		.palette  = VIDEO_PALETTE_YUV410P,
 		.fourcc   = V4L2_PIX_FMT_YUV410,
 		.btformat = BT848_COLOR_FMT_YCrCb411,
 		.depth    = 9,
@@ -606,7 +595,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 2,
 	},{
 		.name     = "4:1:0, planar, Y-Cr-Cb",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_YVU410,
 		.btformat = BT848_COLOR_FMT_YCrCb411,
 		.depth    = 9,
@@ -615,14 +603,13 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 2,
 	},{
 		.name     = "raw scanlines",
-		.palette  = VIDEO_PALETTE_RAW,
 		.fourcc   = -1,
 		.btformat = BT848_COLOR_FMT_RAW,
 		.depth    = 8,
 		.flags    = FORMAT_FLAGS_RAW,
 	}
 };
-static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
+static const unsigned int FORMATS = ARRAY_SIZE(formats);
 
 /* ----------------------------------------------------------------------- */
 
@@ -798,7 +785,17 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
 
 
 };
-static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
+
+static const struct v4l2_queryctrl *ctrl_by_id(int id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++)
+		if (bttv_ctls[i].id == id)
+			return bttv_ctls+i;
+
+	return NULL;
+}
 
 /* ----------------------------------------------------------------------- */
 /* resource management                                                     */
@@ -1254,16 +1251,6 @@ audio_input(struct bttv *btv, int input)
 	return audio_mux(btv, input, btv->mute);
 }
 
-static void
-i2c_vidiocschan(struct bttv *btv)
-{
-	v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
-
-	bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
-	if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
-		bttv_tda9880_setnorm(btv,btv->tvnorm);
-}
-
 static void
 bttv_crop_calc_limits(struct bttv_crop *c)
 {
@@ -1298,6 +1285,7 @@ static int
 set_tvnorm(struct bttv *btv, unsigned int norm)
 {
 	const struct bttv_tvnorm *tvnorm;
+	v4l2_std_id id;
 
 	if (norm < 0 || norm >= BTTV_TVNORMS)
 		return -EINVAL;
@@ -1334,6 +1322,9 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
 		bttv_tda9880_setnorm(btv,norm);
 		break;
 	}
+	id = tvnorm->v4l2_id;
+	bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
+
 	return 0;
 }
 
@@ -1359,7 +1350,6 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm)
 	audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
 		       TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
 	set_tvnorm(btv, norm);
-	i2c_vidiocschan(btv);
 }
 
 static void init_irqreg(struct bttv *btv)
@@ -1452,38 +1442,12 @@ static void bttv_reinit_bt848(struct bttv *btv)
 	set_input(btv, btv->input, btv->tvnorm);
 }
 
-static int get_control(struct bttv *btv, struct v4l2_control *c)
+static int bttv_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *c)
 {
-	struct video_audio va;
-	int i;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-	for (i = 0; i < BTTV_CTLS; i++)
-		if (bttv_ctls[i].id == c->id)
-			break;
-	if (i == BTTV_CTLS)
-		return -EINVAL;
-	if (btv->audio_hook && i >= 4 && i <= 8) {
-		memset(&va,0,sizeof(va));
-		btv->audio_hook(btv,&va,0);
-		switch (c->id) {
-		case V4L2_CID_AUDIO_MUTE:
-			c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
-			break;
-		case V4L2_CID_AUDIO_VOLUME:
-			c->value = va.volume;
-			break;
-		case V4L2_CID_AUDIO_BALANCE:
-			c->value = va.balance;
-			break;
-		case V4L2_CID_AUDIO_BASS:
-			c->value = va.bass;
-			break;
-		case V4L2_CID_AUDIO_TREBLE:
-			c->value = va.treble;
-			break;
-		}
-		return 0;
-	}
 	switch (c->id) {
 	case V4L2_CID_BRIGHTNESS:
 		c->value = btv->bright;
@@ -1503,7 +1467,7 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
-		bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
+		bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c);
 		break;
 
 	case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1545,67 +1509,44 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
 	return 0;
 }
 
-static int set_control(struct bttv *btv, struct v4l2_control *c)
+static int bttv_s_ctrl(struct file *file, void *f,
+					struct v4l2_control *c)
 {
-	struct video_audio va;
-	int i,val;
+	int err;
+	int val;
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-	for (i = 0; i < BTTV_CTLS; i++)
-		if (bttv_ctls[i].id == c->id)
-			break;
-	if (i == BTTV_CTLS)
-		return -EINVAL;
-	if (btv->audio_hook && i >= 4 && i <= 8) {
-		memset(&va,0,sizeof(va));
-		btv->audio_hook(btv,&va,0);
-		switch (c->id) {
-		case V4L2_CID_AUDIO_MUTE:
-			if (c->value) {
-				va.flags |= VIDEO_AUDIO_MUTE;
-				audio_mute(btv, 1);
-			} else {
-				va.flags &= ~VIDEO_AUDIO_MUTE;
-				audio_mute(btv, 0);
-			}
-			break;
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		case V4L2_CID_AUDIO_VOLUME:
-			va.volume = c->value;
-			break;
-		case V4L2_CID_AUDIO_BALANCE:
-			va.balance = c->value;
-			break;
-		case V4L2_CID_AUDIO_BASS:
-			va.bass = c->value;
-			break;
-		case V4L2_CID_AUDIO_TREBLE:
-			va.treble = c->value;
-			break;
-		}
-		btv->audio_hook(btv,&va,1);
-		return 0;
-	}
 	switch (c->id) {
 	case V4L2_CID_BRIGHTNESS:
-		bt848_bright(btv,c->value);
+		bt848_bright(btv, c->value);
 		break;
 	case V4L2_CID_HUE:
-		bt848_hue(btv,c->value);
+		bt848_hue(btv, c->value);
 		break;
 	case V4L2_CID_CONTRAST:
-		bt848_contrast(btv,c->value);
+		bt848_contrast(btv, c->value);
 		break;
 	case V4L2_CID_SATURATION:
-		bt848_sat(btv,c->value);
+		bt848_sat(btv, c->value);
 		break;
 	case V4L2_CID_AUDIO_MUTE:
 		audio_mute(btv, c->value);
 		/* fall through */
 	case V4L2_CID_AUDIO_VOLUME:
+		if (btv->volume_gpio)
+			btv->volume_gpio(btv, c->value);
+
+		bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
+		break;
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
-		bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
+		bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
 		break;
 
 	case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1632,8 +1573,9 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
 		break;
 	case V4L2_CID_PRIVATE_AGC_CRUSH:
 		btv->opt_adc_crush = c->value;
-		btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
-			BT848_ADC);
+		btwrite(BT848_ADC_RESERVED |
+				(btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+				BT848_ADC);
 		break;
 	case V4L2_CID_PRIVATE_VCR_HACK:
 		btv->opt_vcr_hack = c->value;
@@ -1692,30 +1634,16 @@ static void bttv_field_count(struct bttv *btv)
 	}
 }
 
-static const struct bttv_format*
-format_by_palette(int palette)
-{
-	unsigned int i;
-
-	for (i = 0; i < BTTV_FORMATS; i++) {
-		if (-1 == bttv_formats[i].palette)
-			continue;
-		if (bttv_formats[i].palette == palette)
-			return bttv_formats+i;
-	}
-	return NULL;
-}
-
 static const struct bttv_format*
 format_by_fourcc(int fourcc)
 {
 	unsigned int i;
 
-	for (i = 0; i < BTTV_FORMATS; i++) {
-		if (-1 == bttv_formats[i].fourcc)
+	for (i = 0; i < FORMATS; i++) {
+		if (-1 == formats[i].fourcc)
 			continue;
-		if (bttv_formats[i].fourcc == fourcc)
-			return bttv_formats+i;
+		if (formats[i].fourcc == fourcc)
+			return formats+i;
 	}
 	return NULL;
 }
@@ -1733,7 +1661,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
 
 	dprintk("switch_overlay: enter [new=%p]\n",new);
 	if (new)
-		new->vb.state = STATE_DONE;
+		new->vb.state = VIDEOBUF_DONE;
 	spin_lock_irqsave(&btv->s_lock,flags);
 	old = btv->screen;
 	btv->screen = new;
@@ -1844,7 +1772,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
 	}
 
 	/* alloc risc memory */
-	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,&btv->fbuf)))
 			goto fail;
@@ -1854,7 +1782,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
 		if (0 != (rc = bttv_buffer_risc(btv,buf)))
 			goto fail;
 
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	return 0;
 
  fail:
@@ -1893,7 +1821,7 @@ buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 	struct bttv_fh *fh = q->priv_data;
 	struct bttv    *btv = fh->btv;
 
-	buf->vb.state = STATE_QUEUED;
+	buf->vb.state = VIDEOBUF_QUEUED;
 	list_add_tail(&buf->vb.queue,&btv->capture);
 	if (!btv->curr.frame_irq) {
 		btv->loop_irq |= 1;
@@ -1916,399 +1844,259 @@ static struct videobuf_queue_ops bttv_video_qops = {
 	.buf_release  = buffer_release,
 };
 
-static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
+static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-	switch (cmd) {
-	case BTTV_VERSION:
-		return BTTV_VERSION_CODE;
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	unsigned int i;
+	int err;
 
-	/* ***  v4l1  *** ************************************************ */
-	case VIDIOCGFREQ:
-	{
-		unsigned long *freq = arg;
-		*freq = btv->freq;
-		return 0;
-	}
-	case VIDIOCSFREQ:
-	{
-		struct v4l2_frequency freq;
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		memset(&freq, 0, sizeof(freq));
-		freq.frequency = *(unsigned long *)arg;
-		mutex_lock(&btv->lock);
-		freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-		btv->freq = *(unsigned long *)arg;
-		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
-		if (btv->has_matchbox && btv->radio_user)
-			tea5757_set_freq(btv,*(unsigned long *)arg);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	for (i = 0; i < BTTV_TVNORMS; i++)
+		if (*id & bttv_tvnorms[i].v4l2_id)
+			break;
+	if (i == BTTV_TVNORMS)
+		return -EINVAL;
 
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner *v = arg;
+	mutex_lock(&btv->lock);
+	set_tvnorm(btv, i);
+	mutex_unlock(&btv->lock);
 
-		if (UNSET == bttv_tvcards[btv->c.type].tuner)
-			return -EINVAL;
-		if (v->tuner) /* Only tuner 0 */
-			return -EINVAL;
-		strcpy(v->name, "Television");
-		v->rangelow  = 0;
-		v->rangehigh = 0x7FFFFFFF;
-		v->flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
-		v->mode      = btv->tvnorm;
-		v->signal    = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
-		bttv_call_i2c_clients(btv,cmd,v);
-		return 0;
-	}
-	case VIDIOCSTUNER:
-	{
-		struct video_tuner *v = arg;
+	return 0;
+}
 
-		if (v->tuner) /* Only tuner 0 */
-			return -EINVAL;
-		if (v->mode >= BTTV_TVNORMS)
-			return -EINVAL;
+static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		mutex_lock(&btv->lock);
-		set_tvnorm(btv,v->mode);
-		bttv_call_i2c_clients(btv,cmd,v);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
+		*id = V4L2_STD_625_50;
+	else
+		*id = V4L2_STD_525_60;
+	return 0;
+}
 
-	case VIDIOCGCHAN:
-	{
-		struct video_channel *v = arg;
-		unsigned int channel = v->channel;
+static int bttv_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	unsigned int n;
 
-		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-			return -EINVAL;
-		v->tuners=0;
-		v->flags = VIDEO_VC_AUDIO;
-		v->type = VIDEO_TYPE_CAMERA;
-		v->norm = btv->tvnorm;
-		if (channel == bttv_tvcards[btv->c.type].tuner)  {
-			strcpy(v->name,"Television");
-			v->flags|=VIDEO_VC_TUNER;
-			v->type=VIDEO_TYPE_TV;
-			v->tuners=1;
-		} else if (channel == btv->svhs) {
-			strcpy(v->name,"S-Video");
-		} else {
-			sprintf(v->name,"Composite%d",channel);
-		}
-		return 0;
-	}
-	case VIDIOCSCHAN:
-	{
-		struct video_channel *v = arg;
-		unsigned int channel = v->channel;
+	n = i->index;
 
-		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-			return -EINVAL;
-		if (v->norm >= BTTV_TVNORMS)
-			return -EINVAL;
+	if (n >= bttv_tvcards[btv->c.type].video_inputs)
+		return -EINVAL;
 
-		mutex_lock(&btv->lock);
-		if (channel == btv->input &&
-		    v->norm == btv->tvnorm) {
-			/* nothing to do */
-			mutex_unlock(&btv->lock);
-			return 0;
-		}
+	memset(i, 0, sizeof(*i));
 
-		set_input(btv, v->channel, v->norm);
-		mutex_unlock(&btv->lock);
-		return 0;
+	i->index    = n;
+	i->type     = V4L2_INPUT_TYPE_CAMERA;
+	i->audioset = 1;
+
+	if (i->index == bttv_tvcards[btv->c.type].tuner) {
+		sprintf(i->name, "Television");
+		i->type  = V4L2_INPUT_TYPE_TUNER;
+		i->tuner = 0;
+	} else if (i->index == btv->svhs) {
+		sprintf(i->name, "S-Video");
+	} else {
+		sprintf(i->name, "Composite%d", i->index);
 	}
 
-	case VIDIOCGAUDIO:
-	{
-		struct video_audio *v = arg;
+	if (i->index == btv->input) {
+		__u32 dstatus = btread(BT848_DSTATUS);
+		if (0 == (dstatus & BT848_DSTATUS_PRES))
+			i->status |= V4L2_IN_ST_NO_SIGNAL;
+		if (0 == (dstatus & BT848_DSTATUS_HLOC))
+			i->status |= V4L2_IN_ST_NO_H_LOCK;
+	}
 
-		memset(v,0,sizeof(*v));
-		strcpy(v->name,"Television");
-		v->flags |= VIDEO_AUDIO_MUTABLE;
-		v->mode  = VIDEO_SOUND_MONO;
+	for (n = 0; n < BTTV_TVNORMS; n++)
+		i->std |= bttv_tvnorms[n].v4l2_id;
 
-		mutex_lock(&btv->lock);
-		bttv_call_i2c_clients(btv,cmd,v);
+	return 0;
+}
 
-		/* card specific hooks */
-		if (btv->audio_hook)
-			btv->audio_hook(btv,v,0);
+static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
-	case VIDIOCSAUDIO:
-	{
-		struct video_audio *v = arg;
-		unsigned int audio = v->audio;
+	*i = btv->input;
+	return 0;
+}
 
-		if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
-			return -EINVAL;
+static int bttv_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
 
-		mutex_lock(&btv->lock);
-		audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
-		bttv_call_i2c_clients(btv,cmd,v);
+	int err;
 
-		/* card specific hooks */
-		if (btv->audio_hook)
-			btv->audio_hook(btv,v,1);
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	if (i > bttv_tvcards[btv->c.type].video_inputs)
+		return -EINVAL;
 
-	/* ***  v4l2  *** ************************************************ */
-	case VIDIOC_ENUMSTD:
-	{
-		struct v4l2_standard *e = arg;
-		unsigned int index = e->index;
+	mutex_lock(&btv->lock);
+	set_input(btv, i, btv->tvnorm);
+	mutex_unlock(&btv->lock);
+	return 0;
+}
 
-		if (index >= BTTV_TVNORMS)
-			return -EINVAL;
-		v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
-					 bttv_tvnorms[e->index].name);
-		e->index = index;
-		return 0;
-	}
-	case VIDIOC_G_STD:
-	{
-		v4l2_std_id *id = arg;
-		*id = bttv_tvnorms[btv->tvnorm].v4l2_id;
-		return 0;
-	}
-	case VIDIOC_S_STD:
-	{
-		v4l2_std_id *id = arg;
-		unsigned int i;
+static int bttv_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	int err;
 
-		for (i = 0; i < BTTV_TVNORMS; i++)
-			if (*id & bttv_tvnorms[i].v4l2_id)
-				break;
-		if (i == BTTV_TVNORMS)
-			return -EINVAL;
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		mutex_lock(&btv->lock);
-		set_tvnorm(btv,i);
-		i2c_vidiocschan(btv);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
-	case VIDIOC_QUERYSTD:
-	{
-		v4l2_std_id *id = arg;
+	if (UNSET == bttv_tvcards[btv->c.type].tuner)
+		return -EINVAL;
 
-		if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
-			*id = V4L2_STD_625_50;
-		else
-			*id = V4L2_STD_525_60;
-		return 0;
-	}
+	if (0 != t->index)
+		return -EINVAL;
 
-	case VIDIOC_ENUMINPUT:
-	{
-		struct v4l2_input *i = arg;
-		unsigned int n;
+	mutex_lock(&btv->lock);
+	bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
 
-		n = i->index;
-		if (n >= bttv_tvcards[btv->c.type].video_inputs)
-			return -EINVAL;
-		memset(i,0,sizeof(*i));
-		i->index    = n;
-		i->type     = V4L2_INPUT_TYPE_CAMERA;
-		i->audioset = 1;
-		if (i->index == bttv_tvcards[btv->c.type].tuner) {
-			sprintf(i->name, "Television");
-			i->type  = V4L2_INPUT_TYPE_TUNER;
-			i->tuner = 0;
-		} else if (i->index == btv->svhs) {
-			sprintf(i->name, "S-Video");
-		} else {
-			sprintf(i->name,"Composite%d",i->index);
-		}
-		if (i->index == btv->input) {
-			__u32 dstatus = btread(BT848_DSTATUS);
-			if (0 == (dstatus & BT848_DSTATUS_PRES))
-				i->status |= V4L2_IN_ST_NO_SIGNAL;
-			if (0 == (dstatus & BT848_DSTATUS_HLOC))
-				i->status |= V4L2_IN_ST_NO_H_LOCK;
-		}
-		for (n = 0; n < BTTV_TVNORMS; n++)
-			i->std |= bttv_tvnorms[n].v4l2_id;
-		return 0;
-	}
-	case VIDIOC_G_INPUT:
-	{
-		int *i = arg;
-		*i = btv->input;
-		return 0;
-	}
-	case VIDIOC_S_INPUT:
-	{
-		unsigned int *i = arg;
+	if (btv->audio_mode_gpio)
+		btv->audio_mode_gpio(btv, t, 1);
 
-		if (*i > bttv_tvcards[btv->c.type].video_inputs)
-			return -EINVAL;
-		mutex_lock(&btv->lock);
-		set_input(btv, *i, btv->tvnorm);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	mutex_unlock(&btv->lock);
 
-	case VIDIOC_G_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
+	return 0;
+}
 
-		if (UNSET == bttv_tvcards[btv->c.type].tuner)
-			return -EINVAL;
-		if (0 != t->index)
-			return -EINVAL;
-		mutex_lock(&btv->lock);
-		memset(t,0,sizeof(*t));
-		t->rxsubchans = V4L2_TUNER_SUB_MONO;
-		bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
-		strcpy(t->name, "Television");
-		t->capability = V4L2_TUNER_CAP_NORM;
-		t->type       = V4L2_TUNER_ANALOG_TV;
-		if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
-			t->signal = 0xffff;
-
-		if (btv->audio_hook) {
-			/* Hmmm ... */
-			struct video_audio va;
-			memset(&va, 0, sizeof(struct video_audio));
-			btv->audio_hook(btv,&va,0);
-			t->audmode    = V4L2_TUNER_MODE_MONO;
-			t->rxsubchans = V4L2_TUNER_SUB_MONO;
-			if(va.mode & VIDEO_SOUND_STEREO) {
-				t->audmode    = V4L2_TUNER_MODE_STEREO;
-				t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			}
-			if(va.mode & VIDEO_SOUND_LANG2) {
-				t->audmode    = V4L2_TUNER_MODE_LANG1;
-				t->rxsubchans = V4L2_TUNER_SUB_LANG1
-					| V4L2_TUNER_SUB_LANG2;
-			}
-		}
-		/* FIXME: fill capability+audmode */
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
-	case VIDIOC_S_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
+static int bttv_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	int err;
 
-		if (UNSET == bttv_tvcards[btv->c.type].tuner)
-			return -EINVAL;
-		if (0 != t->index)
-			return -EINVAL;
-		mutex_lock(&btv->lock);
-		bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
-		if (btv->audio_hook) {
-			struct video_audio va;
-			memset(&va, 0, sizeof(struct video_audio));
-			if (t->audmode == V4L2_TUNER_MODE_MONO)
-				va.mode = VIDEO_SOUND_MONO;
-			else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
-				 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
-				va.mode = VIDEO_SOUND_STEREO;
-			else if (t->audmode == V4L2_TUNER_MODE_LANG1)
-				va.mode = VIDEO_SOUND_LANG1;
-			else if (t->audmode == V4L2_TUNER_MODE_LANG2)
-				va.mode = VIDEO_SOUND_LANG2;
-			btv->audio_hook(btv,&va,1);
-		}
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-	case VIDIOC_G_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
+	f->type = V4L2_TUNER_ANALOG_TV;
+	f->frequency = btv->freq;
 
-		memset(f,0,sizeof(*f));
-		f->type = V4L2_TUNER_ANALOG_TV;
-		f->frequency = btv->freq;
-		return 0;
-	}
-	case VIDIOC_S_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
+	return 0;
+}
 
-		if (unlikely(f->tuner != 0))
-			return -EINVAL;
-		if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
-			return -EINVAL;
-		mutex_lock(&btv->lock);
-		btv->freq = f->frequency;
-		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
-		if (btv->has_matchbox && btv->radio_user)
-			tea5757_set_freq(btv,btv->freq);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
-	case VIDIOC_LOG_STATUS:
-	{
-		printk(KERN_INFO "bttv%d: =================  START STATUS CARD #%d  =================\n", btv->c.nr, btv->c.nr);
-		bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
-		printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);
-		return 0;
-	}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	case VIDIOC_DBG_G_REGISTER:
-	case VIDIOC_DBG_S_REGISTER:
-	{
-		struct v4l2_register *reg = arg;
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-			return -EINVAL;
-		/* bt848 has a 12-bit register space */
-		reg->reg &= 0xfff;
-		if (cmd == VIDIOC_DBG_G_REGISTER)
-			reg->val = btread(reg->reg);
-		else
-			btwrite(reg->val, reg->reg);
-		return 0;
-	}
-#endif
+static int bttv_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	int err;
 
-	default:
-		return -ENOIOCTLCMD;
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-	}
+	if (unlikely(f->tuner != 0))
+		return -EINVAL;
+	if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
+		return -EINVAL;
+	mutex_lock(&btv->lock);
+	btv->freq = f->frequency;
+	bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f);
+	if (btv->has_matchbox && btv->radio_user)
+		tea5757_set_freq(btv, btv->freq);
+	mutex_unlock(&btv->lock);
 	return 0;
 }
 
-/* Given cropping boundaries b and the scaled width and height of a
-   single field or frame, which must not exceed hardware limits, this
-   function adjusts the cropping parameters c. */
-static void
-bttv_crop_adjust	(struct bttv_crop *             c,
-			 const struct v4l2_rect *	b,
-			 __s32                          width,
-			 __s32                          height,
-			 enum v4l2_field                field)
+static int bttv_log_status(struct file *file, void *f)
 {
-	__s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
-	__s32 max_left;
-	__s32 max_top;
+	struct bttv_fh *fh  = f;
+	struct bttv *btv = fh->btv;
 
-	if (width < c->min_scaled_width) {
-		/* Max. hor. scale factor 16:1. */
-		c->rect.width = width * 16;
-	} else if (width > c->max_scaled_width) {
-		/* Min. hor. scale factor 1:1. */
-		c->rect.width = width;
+	printk(KERN_INFO "bttv%d: ========  START STATUS CARD #%d  ========\n",
+			btv->c.nr, btv->c.nr);
+	bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
+	printk(KERN_INFO "bttv%d: ========  END STATUS CARD   #%d  ========\n",
+			btv->c.nr, btv->c.nr);
+	return 0;
+}
 
-		max_left = b->left + b->width - width;
-		max_left = min(max_left, (__s32) MAX_HDELAY);
-		if (c->rect.left > max_left)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int bttv_g_register(struct file *file, void *f,
+					struct v4l2_register *reg)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+
+	/* bt848 has a 12-bit register space */
+	reg->reg &= 0xfff;
+	reg->val = btread(reg->reg);
+
+	return 0;
+}
+
+static int bttv_s_register(struct file *file, void *f,
+					struct v4l2_register *reg)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+
+	/* bt848 has a 12-bit register space */
+	reg->reg &= 0xfff;
+	btwrite(reg->val, reg->reg);
+
+	return 0;
+}
+#endif
+
+/* Given cropping boundaries b and the scaled width and height of a
+   single field or frame, which must not exceed hardware limits, this
+   function adjusts the cropping parameters c. */
+static void
+bttv_crop_adjust	(struct bttv_crop *             c,
+			 const struct v4l2_rect *	b,
+			 __s32                          width,
+			 __s32                          height,
+			 enum v4l2_field                field)
+{
+	__s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
+	__s32 max_left;
+	__s32 max_top;
+
+	if (width < c->min_scaled_width) {
+		/* Max. hor. scale factor 16:1. */
+		c->rect.width = width * 16;
+	} else if (width > c->max_scaled_width) {
+		/* Min. hor. scale factor 1:1. */
+		c->rect.width = width;
+
+		max_left = b->left + b->width - width;
+		max_left = min(max_left, (__s32) MAX_HDELAY);
+		if (c->rect.left > max_left)
 			c->rect.left = max_left;
 	}
 
@@ -2659,983 +2447,681 @@ pix_format_set_size     (struct v4l2_pix_format *       f,
 	}
 }
 
-static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+static int bttv_g_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
 {
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
-		pix_format_set_size (&f->fmt.pix, fh->fmt,
-				     fh->width, fh->height);
-		f->fmt.pix.field        = fh->cap.field;
-		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-		return 0;
-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-		memset(&f->fmt.win,0,sizeof(struct v4l2_window));
-		f->fmt.win.w     = fh->ov.w;
-		f->fmt.win.field = fh->ov.field;
-		return 0;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		bttv_vbi_get_fmt(fh, &f->fmt.vbi);
-		return 0;
-	default:
-		return -EINVAL;
-	}
+	struct bttv_fh *fh  = priv;
+
+	pix_format_set_size(&f->fmt.pix, fh->fmt,
+				fh->width, fh->height);
+	f->fmt.pix.field        = fh->cap.field;
+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+
+	return 0;
 }
 
-static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
-			struct v4l2_format *f, int adjust_crop)
+static int bttv_g_fmt_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
 {
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-	{
-		const struct bttv_format *fmt;
-		enum v4l2_field field;
-		__s32 width, height;
-		int rc;
+	struct bttv_fh *fh  = priv;
 
-		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-		if (NULL == fmt)
-			return -EINVAL;
+	f->fmt.win.w     = fh->ov.w;
+	f->fmt.win.field = fh->ov.field;
 
-		field = f->fmt.pix.field;
-		if (V4L2_FIELD_ANY == field) {
-			__s32 height2;
+	return 0;
+}
 
-			height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
-			field = (f->fmt.pix.height > height2)
-				? V4L2_FIELD_INTERLACED
-				: V4L2_FIELD_BOTTOM;
-		}
-		if (V4L2_FIELD_SEQ_BT == field)
-			field = V4L2_FIELD_SEQ_TB;
-		switch (field) {
-		case V4L2_FIELD_TOP:
-		case V4L2_FIELD_BOTTOM:
-		case V4L2_FIELD_ALTERNATE:
-		case V4L2_FIELD_INTERLACED:
-			break;
-		case V4L2_FIELD_SEQ_TB:
-			if (fmt->flags & FORMAT_FLAGS_PLANAR)
-				return -EINVAL;
-			break;
-		default:
-			return -EINVAL;
-		}
+static int bttv_try_fmt_cap(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	const struct bttv_format *fmt;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	enum v4l2_field field;
+	__s32 width, height;
+	int rc;
 
-		width = f->fmt.pix.width;
-		height = f->fmt.pix.height;
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
 
-		rc = limit_scaled_size(fh, &width, &height, field,
-				       /* width_mask: 4 pixels */ ~3,
-				       /* width_bias: nearest */ 2,
-				       /* adjust_size */ 1,
-				       adjust_crop);
-		if (0 != rc)
-			return rc;
+	field = f->fmt.pix.field;
 
-		/* update data for the application */
-		f->fmt.pix.field = field;
-		pix_format_set_size(&f->fmt.pix, fmt, width, height);
+	if (V4L2_FIELD_ANY == field) {
+		__s32 height2;
 
-		return 0;
+		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+		field = (f->fmt.pix.height > height2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
 	}
-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-		return verify_window(fh, &f->fmt.win,
-				     /* adjust_size */ 1,
-				     /* adjust_crop */ 0);
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
+
+	if (V4L2_FIELD_SEQ_BT == field)
+		field = V4L2_FIELD_SEQ_TB;
+
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+	case V4L2_FIELD_ALTERNATE:
+	case V4L2_FIELD_INTERLACED:
+		break;
+	case V4L2_FIELD_SEQ_TB:
+		if (fmt->flags & FORMAT_FLAGS_PLANAR)
+			return -EINVAL;
+		break;
 	default:
 		return -EINVAL;
 	}
+
+	width = f->fmt.pix.width;
+	height = f->fmt.pix.height;
+
+	rc = limit_scaled_size(fh, &width, &height, field,
+			       /* width_mask: 4 pixels */ ~3,
+			       /* width_bias: nearest */ 2,
+			       /* adjust_size */ 1,
+			       /* adjust_crop */ 0);
+	if (0 != rc)
+		return rc;
+
+	/* update data for the application */
+	f->fmt.pix.field = field;
+	pix_format_set_size(&f->fmt.pix, fmt, width, height);
+
+	return 0;
+}
+
+static int bttv_try_fmt_overlay(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	struct bttv_fh *fh = priv;
+
+	return verify_window(fh, &f->fmt.win,
+			/* adjust_size */ 1,
+			/* adjust_crop */ 0);
 }
 
-static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
-		      struct v4l2_format *f)
+static int bttv_s_fmt_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
 {
 	int retval;
+	const struct bttv_format *fmt;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	__s32 width, height;
+	enum v4l2_field field;
 
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-	{
-		const struct bttv_format *fmt;
+	retval = bttv_switch_type(fh, f->type);
+	if (0 != retval)
+		return retval;
 
-		retval = bttv_switch_type(fh,f->type);
-		if (0 != retval)
-			return retval;
-		retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
-		if (0 != retval)
-			return retval;
-		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	retval = bttv_try_fmt_cap(file, priv, f);
+	if (0 != retval)
+		return retval;
 
-		/* update our state informations */
-		mutex_lock(&fh->cap.lock);
-		fh->fmt              = fmt;
-		fh->cap.field        = f->fmt.pix.field;
-		fh->cap.last         = V4L2_FIELD_NONE;
-		fh->width            = f->fmt.pix.width;
-		fh->height           = f->fmt.pix.height;
-		btv->init.fmt        = fmt;
-		btv->init.width      = f->fmt.pix.width;
-		btv->init.height     = f->fmt.pix.height;
-		mutex_unlock(&fh->cap.lock);
+	width = f->fmt.pix.width;
+	height = f->fmt.pix.height;
+	field = f->fmt.pix.field;
 
-		return 0;
-	}
-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-		if (no_overlay > 0) {
-			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-			return -EINVAL;
-		}
-		return setup_window(fh, btv, &f->fmt.win, 1);
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		retval = bttv_switch_type(fh,f->type);
-		if (0 != retval)
-			return retval;
-		return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
-	default:
+	retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field,
+			       /* width_mask: 4 pixels */ ~3,
+			       /* width_bias: nearest */ 2,
+			       /* adjust_size */ 1,
+			       /* adjust_crop */ 1);
+	if (0 != retval)
+		return retval;
+
+	f->fmt.pix.field = field;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+
+	/* update our state informations */
+	mutex_lock(&fh->cap.lock);
+	fh->fmt              = fmt;
+	fh->cap.field        = f->fmt.pix.field;
+	fh->cap.last         = V4L2_FIELD_NONE;
+	fh->width            = f->fmt.pix.width;
+	fh->height           = f->fmt.pix.height;
+	btv->init.fmt        = fmt;
+	btv->init.width      = f->fmt.pix.width;
+	btv->init.height     = f->fmt.pix.height;
+	mutex_unlock(&fh->cap.lock);
+
+	return 0;
+}
+
+static int bttv_s_fmt_overlay(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
 		return -EINVAL;
 	}
+
+	return setup_window(fh, btv, &f->fmt.win, 1);
 }
 
-static int bttv_do_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
 {
-	struct bttv_fh *fh  = file->private_data;
-	struct bttv    *btv = fh->btv;
-	unsigned long flags;
-	int retval = 0;
+	int retval;
+	unsigned int i;
+	struct bttv_fh *fh = priv;
 
-	if (bttv_debug > 1)
-		v4l_print_ioctl(btv->c.name, cmd);
-
-	if (btv->errors)
-		bttv_reinit_bt848(btv);
-
-	switch (cmd) {
-	case VIDIOCSFREQ:
-	case VIDIOCSTUNER:
-	case VIDIOCSCHAN:
-	case VIDIOC_S_CTRL:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_S_FREQUENCY:
-		retval = v4l2_prio_check(&btv->prio,&fh->prio);
-		if (0 != retval)
-			return retval;
-	};
+	mutex_lock(&fh->cap.lock);
+	retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
+				     V4L2_MEMORY_MMAP);
+	if (retval < 0) {
+		mutex_unlock(&fh->cap.lock);
+		return retval;
+	}
 
-	switch (cmd) {
+	gbuffers = retval;
+	memset(mbuf, 0, sizeof(*mbuf));
+	mbuf->frames = gbuffers;
+	mbuf->size   = gbuffers * gbufsize;
 
-	/* ***  v4l1  *** ************************************************ */
-	case VIDIOCGCAP:
-	{
-		struct video_capability *cap = arg;
+	for (i = 0; i < gbuffers; i++)
+		mbuf->offsets[i] = i * gbufsize;
 
-		memset(cap,0,sizeof(*cap));
-		strcpy(cap->name,btv->video_dev->name);
-		if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-			/* vbi */
-			cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
-		} else {
-			/* others */
-			cap->type = VID_TYPE_CAPTURE|
-				VID_TYPE_TUNER|
-				VID_TYPE_CLIPPING|
-				VID_TYPE_SCALES;
-			if (no_overlay <= 0)
-				cap->type |= VID_TYPE_OVERLAY;
-
-			cap->maxwidth  = bttv_tvnorms[btv->tvnorm].swidth;
-			cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
-			cap->minwidth  = 48;
-			cap->minheight = 32;
-		}
-		cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
-		cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
-		return 0;
-	}
+	mutex_unlock(&fh->cap.lock);
+	return 0;
+}
+#endif
 
-	case VIDIOCGPICT:
-	{
-		struct video_picture *pic = arg;
-
-		memset(pic,0,sizeof(*pic));
-		pic->brightness = btv->bright;
-		pic->contrast   = btv->contrast;
-		pic->hue        = btv->hue;
-		pic->colour     = btv->saturation;
-		if (fh->fmt) {
-			pic->depth   = fh->fmt->depth;
-			pic->palette = fh->fmt->palette;
-		}
-		return 0;
-	}
-	case VIDIOCSPICT:
-	{
-		struct video_picture *pic = arg;
-		const struct bttv_format *fmt;
+static int bttv_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-		fmt = format_by_palette(pic->palette);
-		if (NULL == fmt)
-			return -EINVAL;
-		mutex_lock(&fh->cap.lock);
-		if (fmt->flags & FORMAT_FLAGS_RAW) {
-			/* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
-			   RAW_LINES * 2. F1 is stored at offset 0, F2
-			   at buffer size / 2. */
-			fh->width = RAW_BPL;
-			fh->height = gbufsize / RAW_BPL;
-			btv->init.width  = RAW_BPL;
-			btv->init.height = gbufsize / RAW_BPL;
-		}
-		fh->ovfmt   = fmt;
-		fh->fmt     = fmt;
-		btv->init.ovfmt   = fmt;
-		btv->init.fmt     = fmt;
-		if (bigendian) {
-			/* dirty hack time:  swap bytes for overlay if the
-			   display adaptor is big endian (insmod option) */
-			if (fmt->palette == VIDEO_PALETTE_RGB555 ||
-			    fmt->palette == VIDEO_PALETTE_RGB565 ||
-			    fmt->palette == VIDEO_PALETTE_RGB32) {
-				fh->ovfmt = fmt+1;
-			}
-		}
-		bt848_bright(btv,pic->brightness);
-		bt848_contrast(btv,pic->contrast);
-		bt848_hue(btv,pic->hue);
-		bt848_sat(btv,pic->colour);
-		mutex_unlock(&fh->cap.lock);
-		return 0;
-	}
+	if (0 == v4l2)
+		return -EINVAL;
 
-	case VIDIOCGWIN:
-	{
-		struct video_window *win = arg;
+	strlcpy(cap->driver, "bttv", sizeof(cap->driver));
+	strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "PCI:%s", pci_name(btv->c.pci));
+	cap->version = BTTV_VERSION_CODE;
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_VBI_CAPTURE |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING;
+	if (no_overlay <= 0)
+		cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+
+	if (bttv_tvcards[btv->c.type].tuner != UNSET &&
+	    bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
+		cap->capabilities |= V4L2_CAP_TUNER;
+	return 0;
+}
 
-		memset(win,0,sizeof(*win));
-		win->x      = fh->ov.w.left;
-		win->y      = fh->ov.w.top;
-		win->width  = fh->ov.w.width;
-		win->height = fh->ov.w.height;
-		return 0;
-	}
-	case VIDIOCSWIN:
-	{
-		struct video_window *win = arg;
-		struct v4l2_window w2;
+static int bttv_enum_fmt_vbi(struct file *file, void  *priv,
+				struct v4l2_fmtdesc *f)
+{
+	if (0 != f->index)
+		return -EINVAL;
 
-		if (no_overlay > 0) {
-			printk ("VIDIOCSWIN: no_overlay\n");
-			return -EINVAL;
-		}
+	f->pixelformat = V4L2_PIX_FMT_GREY;
+	strcpy(f->description, "vbi data");
 
-		w2.field = V4L2_FIELD_ANY;
-		w2.w.left    = win->x;
-		w2.w.top     = win->y;
-		w2.w.width   = win->width;
-		w2.w.height  = win->height;
-		w2.clipcount = win->clipcount;
-		w2.clips     = (struct v4l2_clip __user *)win->clips;
-		retval = setup_window(fh, btv, &w2, 0);
-		if (0 == retval) {
-			/* on v4l1 this ioctl affects the read() size too */
-			fh->width  = fh->ov.w.width;
-			fh->height = fh->ov.w.height;
-			btv->init.width  = fh->ov.w.width;
-			btv->init.height = fh->ov.w.height;
-		}
-		return retval;
-	}
+	return 0;
+}
 
-	case VIDIOCGFBUF:
-	{
-		struct video_buffer *fbuf = arg;
-
-		fbuf->base          = btv->fbuf.base;
-		fbuf->width         = btv->fbuf.fmt.width;
-		fbuf->height        = btv->fbuf.fmt.height;
-		fbuf->bytesperline  = btv->fbuf.fmt.bytesperline;
-		if (fh->ovfmt)
-			fbuf->depth = fh->ovfmt->depth;
-		else {
-			if (fbuf->width)
-				fbuf->depth   = ((fbuf->bytesperline<<3)
-						  + (fbuf->width-1) )
-						  /fbuf->width;
-			else
-				fbuf->depth = 0;
-		}
-		return 0;
-	}
-	case VIDIOCSFBUF:
-	{
-		struct video_buffer *fbuf = arg;
-		const struct bttv_format *fmt;
-		unsigned long end;
-
-		if(!capable(CAP_SYS_ADMIN) &&
-		   !capable(CAP_SYS_RAWIO))
-			return -EPERM;
-		end = (unsigned long)fbuf->base +
-			fbuf->height * fbuf->bytesperline;
-		mutex_lock(&fh->cap.lock);
-		retval = -EINVAL;
+static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
+{
+	int index = -1, i;
 
-		switch (fbuf->depth) {
-		case 8:
-			fmt = format_by_palette(VIDEO_PALETTE_HI240);
-			break;
-		case 16:
-			fmt = format_by_palette(VIDEO_PALETTE_RGB565);
-			break;
-		case 24:
-			fmt = format_by_palette(VIDEO_PALETTE_RGB24);
-			break;
-		case 32:
-			fmt = format_by_palette(VIDEO_PALETTE_RGB32);
-			break;
-		case 15:
-			fbuf->depth = 16;
-			fmt = format_by_palette(VIDEO_PALETTE_RGB555);
-			break;
-		default:
-			fmt = NULL;
+	for (i = 0; i < FORMATS; i++) {
+		if (formats[i].fourcc != -1)
+			index++;
+		if ((unsigned int)index == f->index)
 			break;
-		}
-		if (NULL == fmt)
-			goto fh_unlock_and_return;
-
-		fh->ovfmt = fmt;
-		fh->fmt   = fmt;
-		btv->init.ovfmt = fmt;
-		btv->init.fmt   = fmt;
-		btv->fbuf.base             = fbuf->base;
-		btv->fbuf.fmt.width        = fbuf->width;
-		btv->fbuf.fmt.height       = fbuf->height;
-		if (fbuf->bytesperline)
-			btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
-		else
-			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
-		mutex_unlock(&fh->cap.lock);
-		return 0;
 	}
+	if (FORMATS == i)
+		return -EINVAL;
 
-	case VIDIOCCAPTURE:
-	case VIDIOC_OVERLAY:
-	{
-		struct bttv_buffer *new;
-		int *on = arg;
+	f->pixelformat = formats[i].fourcc;
+	strlcpy(f->description, formats[i].name, sizeof(f->description));
 
-		if (*on) {
-			/* verify args */
-			if (NULL == btv->fbuf.base)
-				return -EINVAL;
-			if (!fh->ov.setup_ok) {
-				dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
-				return -EINVAL;
-			}
-		}
+	return i;
+}
 
-		if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
-			return -EBUSY;
+static int bttv_enum_fmt_cap(struct file *file, void  *priv,
+				struct v4l2_fmtdesc *f)
+{
+	int rc = bttv_enum_fmt_cap_ovr(f);
 
-		mutex_lock(&fh->cap.lock);
-		if (*on) {
-			fh->ov.tvnorm = btv->tvnorm;
-			new = videobuf_pci_alloc(sizeof(*new));
-			new->crop = btv->crop[!!fh->do_crop].rect;
-			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
-		} else {
-			new = NULL;
-		}
+	if (rc < 0)
+		return rc;
 
-		/* switch over */
-		retval = bttv_switch_overlay(btv,fh,new);
-		mutex_unlock(&fh->cap.lock);
-		return retval;
+	return 0;
+}
+
+static int bttv_enum_fmt_overlay(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	int rc;
+
+	if (no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
 	}
 
-	case VIDIOCGMBUF:
-	{
-		struct video_mbuf *mbuf = arg;
-		unsigned int i;
+	rc = bttv_enum_fmt_cap_ovr(f);
 
-		retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
-					     V4L2_MEMORY_MMAP);
-		if (retval < 0)
-			return retval;
+	if (rc < 0)
+		return rc;
 
-		gbuffers = retval;
-		memset(mbuf,0,sizeof(*mbuf));
-		mbuf->frames = gbuffers;
-		mbuf->size   = gbuffers * gbufsize;
-		for (i = 0; i < gbuffers; i++)
-			mbuf->offsets[i] = i * gbufsize;
-		return 0;
-	}
-	case VIDIOCMCAPTURE:
-	{
-		struct video_mmap *vm = arg;
-		struct bttv_buffer *buf;
-		enum v4l2_field field;
-		__s32 height2;
-		int res;
+	if (!(formats[rc].flags & FORMAT_FLAGS_PACKED))
+		return -EINVAL;
 
-		if (vm->frame >= VIDEO_MAX_FRAME)
-			return -EINVAL;
+	return 0;
+}
 
-		res = bttv_resource(fh);
-		if (!check_alloc_btres(btv, fh, res))
-			return -EBUSY;
+static int bttv_g_fbuf(struct file *file, void *f,
+				struct v4l2_framebuffer *fb)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		mutex_lock(&fh->cap.lock);
-		retval = -EINVAL;
-		buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
-		if (NULL == buf)
-			goto fh_unlock_and_return;
-		if (0 == buf->vb.baddr)
-			goto fh_unlock_and_return;
-		if (buf->vb.state == STATE_QUEUED ||
-		    buf->vb.state == STATE_ACTIVE)
-			goto fh_unlock_and_return;
+	*fb = btv->fbuf;
+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+	if (fh->ovfmt)
+		fb->fmt.pixelformat  = fh->ovfmt->fourcc;
+	return 0;
+}
 
-		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
-		field = (vm->height > height2)
-			? V4L2_FIELD_INTERLACED
-			: V4L2_FIELD_BOTTOM;
-		retval = bttv_prepare_buffer(&fh->cap,btv,buf,
-					     format_by_palette(vm->format),
-					     vm->width,vm->height,field);
-		if (0 != retval)
-			goto fh_unlock_and_return;
-		btv->init.width = vm->width;
-		btv->init.height = vm->height;
-		spin_lock_irqsave(&btv->s_lock,flags);
-		buffer_queue(&fh->cap,&buf->vb);
-		spin_unlock_irqrestore(&btv->s_lock,flags);
-		mutex_unlock(&fh->cap.lock);
-		return 0;
-	}
-	case VIDIOCSYNC:
-	{
-		int *frame = arg;
-		struct bttv_buffer *buf;
+static int bttv_overlay(struct file *file, void *f, unsigned int on)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	struct bttv_buffer *new;
+	int retval;
 
-		if (*frame >= VIDEO_MAX_FRAME)
+	if (on) {
+		/* verify args */
+		if (NULL == btv->fbuf.base)
 			return -EINVAL;
+		if (!fh->ov.setup_ok) {
+			dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
+			return -EINVAL;
+		}
+	}
 
-		mutex_lock(&fh->cap.lock);
-		retval = -EINVAL;
-		buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
-		if (NULL == buf)
-			goto fh_unlock_and_return;
-		retval = videobuf_waiton(&buf->vb,0,1);
+	if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
+		return -EBUSY;
+
+	mutex_lock(&fh->cap.lock);
+	if (on) {
+		fh->ov.tvnorm = btv->tvnorm;
+		new = videobuf_pci_alloc(sizeof(*new));
+		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+	} else {
+		new = NULL;
+	}
+
+	/* switch over */
+	retval = bttv_switch_overlay(btv, fh, new);
+	mutex_unlock(&fh->cap.lock);
+	return retval;
+}
+
+static int bttv_s_fbuf(struct file *file, void *f,
+				struct v4l2_framebuffer *fb)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	const struct bttv_format *fmt;
+	int retval;
+
+	if (!capable(CAP_SYS_ADMIN) &&
+		!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* check args */
+	fmt = format_by_fourcc(fb->fmt.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+	if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
+		return -EINVAL;
+
+	retval = -EINVAL;
+	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+		__s32 width = fb->fmt.width;
+		__s32 height = fb->fmt.height;
+
+		retval = limit_scaled_size(fh, &width, &height,
+					   V4L2_FIELD_INTERLACED,
+					   /* width_mask */ ~3,
+					   /* width_bias */ 2,
+					   /* adjust_size */ 0,
+					   /* adjust_crop */ 0);
 		if (0 != retval)
-			goto fh_unlock_and_return;
-		switch (buf->vb.state) {
-		case STATE_ERROR:
-			retval = -EIO;
-			/* fall through */
-		case STATE_DONE:
-		{
-			struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-			videobuf_dma_sync(&fh->cap,dma);
-			bttv_dma_free(&fh->cap,btv,buf);
-			break;
-		}
-		default:
-			retval = -EINVAL;
-			break;
-		}
-		mutex_unlock(&fh->cap.lock);
-		return retval;
+			return retval;
 	}
 
-	case VIDIOCGVBIFMT:
-		if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
-			retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-			if (0 != retval)
-				return retval;
-		}
+	/* ok, accept it */
+	mutex_lock(&fh->cap.lock);
+	btv->fbuf.base       = fb->base;
+	btv->fbuf.fmt.width  = fb->fmt.width;
+	btv->fbuf.fmt.height = fb->fmt.height;
+	if (0 != fb->fmt.bytesperline)
+		btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
+	else
+		btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
 
-		/* fall through */
+	retval = 0;
+	fh->ovfmt = fmt;
+	btv->init.ovfmt = fmt;
+	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+		fh->ov.w.left   = 0;
+		fh->ov.w.top    = 0;
+		fh->ov.w.width  = fb->fmt.width;
+		fh->ov.w.height = fb->fmt.height;
+		btv->init.ov.w.width  = fb->fmt.width;
+		btv->init.ov.w.height = fb->fmt.height;
+			kfree(fh->ov.clips);
+		fh->ov.clips = NULL;
+		fh->ov.nclips = 0;
+
+		if (check_btres(fh, RESOURCE_OVERLAY)) {
+			struct bttv_buffer *new;
+
+			new = videobuf_pci_alloc(sizeof(*new));
+			new->crop = btv->crop[!!fh->do_crop].rect;
+			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+			retval = bttv_switch_overlay(btv, fh, new);
+		}
+	}
+	mutex_unlock(&fh->cap.lock);
+	return retval;
+}
 
-	case VIDIOCSVBIFMT:
-		return v4l_compat_translate_ioctl(inode, file, cmd,
-						  arg, bttv_do_ioctl);
-
-	case BTTV_VERSION:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGTUNER:
-	case VIDIOCSTUNER:
-	case VIDIOCGCHAN:
-	case VIDIOCSCHAN:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-		return bttv_common_ioctls(btv,cmd,arg);
-
-	/* ***  v4l2  *** ************************************************ */
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability *cap = arg;
+static int bttv_reqbufs(struct file *file, void *priv,
+				struct v4l2_requestbuffers *p)
+{
+	struct bttv_fh *fh = priv;
+	return videobuf_reqbufs(bttv_queue(fh), p);
+}
 
-		if (0 == v4l2)
-			return -EINVAL;
-		memset(cap, 0, sizeof (*cap));
-		strlcpy(cap->driver, "bttv", sizeof (cap->driver));
-		strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
-		snprintf(cap->bus_info, sizeof (cap->bus_info),
-			 "PCI:%s", pci_name(btv->c.pci));
-		cap->version = BTTV_VERSION_CODE;
-		cap->capabilities =
-			V4L2_CAP_VIDEO_CAPTURE |
-			V4L2_CAP_VBI_CAPTURE |
-			V4L2_CAP_READWRITE |
-			V4L2_CAP_STREAMING;
-		if (no_overlay <= 0)
-			cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
-
-		if (bttv_tvcards[btv->c.type].tuner != UNSET &&
-		    bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
-			cap->capabilities |= V4L2_CAP_TUNER;
-		return 0;
-	}
+static int bttv_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *b)
+{
+	struct bttv_fh *fh = priv;
+	return videobuf_querybuf(bttv_queue(fh), b);
+}
 
-	case VIDIOC_ENUM_FMT:
-	{
-		struct v4l2_fmtdesc *f = arg;
-		enum v4l2_buf_type type;
-		unsigned int i;
-		int index;
-
-		type  = f->type;
-		if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
-			/* vbi */
-			index = f->index;
-			if (0 != index)
-				return -EINVAL;
-			memset(f,0,sizeof(*f));
-			f->index       = index;
-			f->type        = type;
-			f->pixelformat = V4L2_PIX_FMT_GREY;
-			strcpy(f->description,"vbi data");
-			return 0;
-		}
+static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int res = bttv_resource(fh);
 
-		/* video capture + overlay */
-		index = -1;
-		for (i = 0; i < BTTV_FORMATS; i++) {
-			if (bttv_formats[i].fourcc != -1)
-				index++;
-			if ((unsigned int)index == f->index)
-				break;
-		}
-		if (BTTV_FORMATS == i)
-			return -EINVAL;
+	if (!check_alloc_btres(btv, fh, res))
+		return -EBUSY;
 
-		switch (f->type) {
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			break;
-		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
-				return -EINVAL;
-			break;
-		default:
-			return -EINVAL;
-		}
-		memset(f,0,sizeof(*f));
-		f->index       = index;
-		f->type        = type;
-		f->pixelformat = bttv_formats[i].fourcc;
-		strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
-		return 0;
-	}
+	return videobuf_qbuf(bttv_queue(fh), b);
+}
 
-	case VIDIOC_TRY_FMT:
-	{
-		struct v4l2_format *f = arg;
-		return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
-	}
-	case VIDIOC_G_FMT:
-	{
-		struct v4l2_format *f = arg;
-		return bttv_g_fmt(fh,f);
-	}
-	case VIDIOC_S_FMT:
-	{
-		struct v4l2_format *f = arg;
-		return bttv_s_fmt(fh,btv,f);
-	}
+static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct bttv_fh *fh = priv;
+	return videobuf_dqbuf(bttv_queue(fh), b,
+			file->f_flags & O_NONBLOCK);
+}
 
-	case VIDIOC_G_FBUF:
-	{
-		struct v4l2_framebuffer *fb = arg;
+static int bttv_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int res = bttv_resource(fh);
 
-		*fb = btv->fbuf;
-		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-		if (fh->ovfmt)
-			fb->fmt.pixelformat  = fh->ovfmt->fourcc;
-		return 0;
-	}
-	case VIDIOC_S_FBUF:
-	{
-		struct v4l2_framebuffer *fb = arg;
-		const struct bttv_format *fmt;
+	if (!check_alloc_btres(btv, fh, res))
+		return -EBUSY;
+	return videobuf_streamon(bttv_queue(fh));
+}
 
-		if(!capable(CAP_SYS_ADMIN) &&
-		   !capable(CAP_SYS_RAWIO))
-			return -EPERM;
 
-		/* check args */
-		fmt = format_by_fourcc(fb->fmt.pixelformat);
-		if (NULL == fmt)
-			return -EINVAL;
-		if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
-			return -EINVAL;
+static int bttv_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int retval;
+	int res = bttv_resource(fh);
 
-		retval = -EINVAL;
-		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-			__s32 width = fb->fmt.width;
-			__s32 height = fb->fmt.height;
-
-			retval = limit_scaled_size(fh, &width, &height,
-						   V4L2_FIELD_INTERLACED,
-						   /* width_mask */ ~3,
-						   /* width_bias */ 2,
-						   /* adjust_size */ 0,
-						   /* adjust_crop */ 0);
-			if (0 != retval)
-				return retval;
-		}
 
-		/* ok, accept it */
-		mutex_lock(&fh->cap.lock);
-		btv->fbuf.base       = fb->base;
-		btv->fbuf.fmt.width  = fb->fmt.width;
-		btv->fbuf.fmt.height = fb->fmt.height;
-		if (0 != fb->fmt.bytesperline)
-			btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
-		else
-			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
-
-		retval = 0;
-		fh->ovfmt = fmt;
-		btv->init.ovfmt = fmt;
-		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-			fh->ov.w.left   = 0;
-			fh->ov.w.top    = 0;
-			fh->ov.w.width  = fb->fmt.width;
-			fh->ov.w.height = fb->fmt.height;
-			btv->init.ov.w.width  = fb->fmt.width;
-			btv->init.ov.w.height = fb->fmt.height;
-				kfree(fh->ov.clips);
-			fh->ov.clips = NULL;
-			fh->ov.nclips = 0;
-
-			if (check_btres(fh, RESOURCE_OVERLAY)) {
-				struct bttv_buffer *new;
-
-				new = videobuf_pci_alloc(sizeof(*new));
-				new->crop = btv->crop[!!fh->do_crop].rect;
-				bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
-				retval = bttv_switch_overlay(btv,fh,new);
-			}
-		}
-		mutex_unlock(&fh->cap.lock);
+	retval = videobuf_streamoff(bttv_queue(fh));
+	if (retval < 0)
 		return retval;
-	}
+	free_btres(btv, fh, res);
+	return 0;
+}
 
-	case VIDIOC_REQBUFS:
-		return videobuf_reqbufs(bttv_queue(fh),arg);
+static int bttv_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	const struct v4l2_queryctrl *ctrl;
 
-	case VIDIOC_QUERYBUF:
-		return videobuf_querybuf(bttv_queue(fh),arg);
+	if ((c->id <  V4L2_CID_BASE ||
+	     c->id >= V4L2_CID_LASTP1) &&
+	    (c->id <  V4L2_CID_PRIVATE_BASE ||
+	     c->id >= V4L2_CID_PRIVATE_LASTP1))
+		return -EINVAL;
 
-	case VIDIOC_QBUF:
-	{
-		int res = bttv_resource(fh);
+	if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
+		*c = no_ctl;
+	else {
+		ctrl = ctrl_by_id(c->id);
 
-		if (!check_alloc_btres(btv, fh, res))
-			return -EBUSY;
-		return videobuf_qbuf(bttv_queue(fh),arg);
+		*c = (NULL != ctrl) ? *ctrl : no_ctl;
 	}
 
-	case VIDIOC_DQBUF:
-		return videobuf_dqbuf(bttv_queue(fh),arg,
-				      file->f_flags & O_NONBLOCK);
+	return 0;
+}
 
-	case VIDIOC_STREAMON:
-	{
-		int res = bttv_resource(fh);
+static int bttv_g_parm(struct file *file, void *f,
+				struct v4l2_streamparm *parm)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	struct v4l2_standard s;
 
-		if (!check_alloc_btres(btv,fh,res))
-			return -EBUSY;
-		return videobuf_streamon(bttv_queue(fh));
-	}
-	case VIDIOC_STREAMOFF:
-	{
-		int res = bttv_resource(fh);
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
+				 bttv_tvnorms[btv->tvnorm].name);
+	parm->parm.capture.timeperframe = s.frameperiod;
+	return 0;
+}
 
-		retval = videobuf_streamoff(bttv_queue(fh));
-		if (retval < 0)
-			return retval;
-		free_btres(btv,fh,res);
-		return 0;
-	}
+static int bttv_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-	case VIDIOC_QUERYCTRL:
-	{
-		struct v4l2_queryctrl *c = arg;
-		int i;
+	if (UNSET == bttv_tvcards[btv->c.type].tuner)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
 
-		if ((c->id <  V4L2_CID_BASE ||
-		     c->id >= V4L2_CID_LASTP1) &&
-		    (c->id <  V4L2_CID_PRIVATE_BASE ||
-		     c->id >= V4L2_CID_PRIVATE_LASTP1))
-			return -EINVAL;
-		for (i = 0; i < BTTV_CTLS; i++)
-			if (bttv_ctls[i].id == c->id)
-				break;
-		if (i == BTTV_CTLS) {
-			*c = no_ctl;
-			return 0;
-		}
-		*c = bttv_ctls[i];
-		if (btv->audio_hook && i >= 4 && i <= 8) {
-			struct video_audio va;
-			memset(&va,0,sizeof(va));
-			btv->audio_hook(btv,&va,0);
-			switch (bttv_ctls[i].id) {
-			case V4L2_CID_AUDIO_VOLUME:
-				if (!(va.flags & VIDEO_AUDIO_VOLUME))
-					*c = no_ctl;
-				break;
-			case V4L2_CID_AUDIO_BALANCE:
-				if (!(va.flags & VIDEO_AUDIO_BALANCE))
-					*c = no_ctl;
-				break;
-			case V4L2_CID_AUDIO_BASS:
-				if (!(va.flags & VIDEO_AUDIO_BASS))
-					*c = no_ctl;
-				break;
-			case V4L2_CID_AUDIO_TREBLE:
-				if (!(va.flags & VIDEO_AUDIO_TREBLE))
-					*c = no_ctl;
-				break;
-			}
-		}
-		return 0;
-	}
-	case VIDIOC_G_CTRL:
-		return get_control(btv,arg);
-	case VIDIOC_S_CTRL:
-		return set_control(btv,arg);
-	case VIDIOC_G_PARM:
-	{
-		struct v4l2_streamparm *parm = arg;
-		struct v4l2_standard s;
-		if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		memset(parm,0,sizeof(*parm));
-		v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
-					 bttv_tvnorms[btv->tvnorm].name);
-		parm->parm.capture.timeperframe = s.frameperiod;
-		return 0;
-	}
+	mutex_lock(&btv->lock);
+	memset(t, 0, sizeof(*t));
+	t->rxsubchans = V4L2_TUNER_SUB_MONO;
+	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+	strcpy(t->name, "Television");
+	t->capability = V4L2_TUNER_CAP_NORM;
+	t->type       = V4L2_TUNER_ANALOG_TV;
+	if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
+		t->signal = 0xffff;
+
+	if (btv->audio_mode_gpio)
+		btv->audio_mode_gpio(btv, t, 0);
 
-	case VIDIOC_G_PRIORITY:
-	{
-		enum v4l2_priority *p = arg;
+	mutex_unlock(&btv->lock);
+	return 0;
+}
 
-		*p = v4l2_prio_max(&btv->prio);
-		return 0;
-	}
-	case VIDIOC_S_PRIORITY:
-	{
-		enum v4l2_priority *prio = arg;
+static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
-	}
+	*p = v4l2_prio_max(&btv->prio);
 
-	case VIDIOC_CROPCAP:
-	{
-		struct v4l2_cropcap *cap = arg;
-		enum v4l2_buf_type type;
+	return 0;
+}
 
-		type = cap->type;
+static int bttv_s_priority(struct file *file, void *f,
+					enum v4l2_priority prio)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-			return -EINVAL;
+	return v4l2_prio_change(&btv->prio, &fh->prio, prio);
+}
 
-		*cap = bttv_tvnorms[btv->tvnorm].cropcap;
-		cap->type = type;
+static int bttv_cropcap(struct file *file, void *priv,
+				struct v4l2_cropcap *cap)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-		return 0;
-	}
-	case VIDIOC_G_CROP:
-	{
-		struct v4l2_crop * crop = arg;
+	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
 
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-			return -EINVAL;
+	*cap = bttv_tvnorms[btv->tvnorm].cropcap;
 
-		/* No fh->do_crop = 1; because btv->crop[1] may be
-		   inconsistent with fh->width or fh->height and apps
-		   do not expect a change here. */
+	return 0;
+}
 
-		crop->c = btv->crop[!!fh->do_crop].rect;
+static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		return 0;
-	}
-	case VIDIOC_S_CROP:
-	{
-		struct v4l2_crop *crop = arg;
-		const struct v4l2_rect *b;
-		struct bttv_crop c;
-		__s32 b_left;
-		__s32 b_top;
-		__s32 b_right;
-		__s32 b_bottom;
-
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-			return -EINVAL;
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
 
-		retval = v4l2_prio_check(&btv->prio,&fh->prio);
-		if (0 != retval)
-			return retval;
+	/* No fh->do_crop = 1; because btv->crop[1] may be
+	   inconsistent with fh->width or fh->height and apps
+	   do not expect a change here. */
 
-		/* Make sure tvnorm, vbi_end and the current cropping
-		   parameters remain consistent until we're done. Note
-		   read() may change vbi_end in check_alloc_btres(). */
-		mutex_lock(&btv->lock);
+	crop->c = btv->crop[!!fh->do_crop].rect;
 
-		retval = -EBUSY;
+	return 0;
+}
 
-		if (locked_btres(fh->btv, VIDEO_RESOURCES))
-			goto btv_unlock_and_return;
+static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	const struct v4l2_rect *b;
+	int retval;
+	struct bttv_crop c;
+	__s32 b_left;
+	__s32 b_top;
+	__s32 b_right;
+	__s32 b_bottom;
 
-		b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
 
-		b_left = b->left;
-		b_right = b_left + b->width;
-		b_bottom = b->top + b->height;
+	retval = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != retval)
+		return retval;
 
-		b_top = max(b->top, btv->vbi_end);
-		if (b_top + 32 >= b_bottom)
-			goto btv_unlock_and_return;
+	/* Make sure tvnorm, vbi_end and the current cropping
+	   parameters remain consistent until we're done. Note
+	   read() may change vbi_end in check_alloc_btres(). */
+	mutex_lock(&btv->lock);
 
-		/* Min. scaled size 48 x 32. */
-		c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
-		c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
+	retval = -EBUSY;
 
-		c.rect.width = clamp(crop->c.width,
-				     48, b_right - c.rect.left);
+	if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
+		mutex_unlock(&btv->lock);
+		return retval;
+	}
 
-		c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
-		/* Top and height must be a multiple of two. */
-		c.rect.top = (c.rect.top + 1) & ~1;
+	b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
 
-		c.rect.height = clamp(crop->c.height,
-				      32, b_bottom - c.rect.top);
-		c.rect.height = (c.rect.height + 1) & ~1;
+	b_left = b->left;
+	b_right = b_left + b->width;
+	b_bottom = b->top + b->height;
 
-		bttv_crop_calc_limits(&c);
+	b_top = max(b->top, btv->vbi_end);
+	if (b_top + 32 >= b_bottom) {
+		mutex_unlock(&btv->lock);
+		return retval;
+	}
 
-		btv->crop[1] = c;
+	/* Min. scaled size 48 x 32. */
+	c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
+	c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
 
-		mutex_unlock(&btv->lock);
+	c.rect.width = clamp(crop->c.width,
+			     48, b_right - c.rect.left);
 
-		fh->do_crop = 1;
+	c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
+	/* Top and height must be a multiple of two. */
+	c.rect.top = (c.rect.top + 1) & ~1;
 
-		mutex_lock(&fh->cap.lock);
+	c.rect.height = clamp(crop->c.height,
+			      32, b_bottom - c.rect.top);
+	c.rect.height = (c.rect.height + 1) & ~1;
 
-		if (fh->width < c.min_scaled_width) {
-			fh->width = c.min_scaled_width;
-			btv->init.width = c.min_scaled_width;
-		} else if (fh->width > c.max_scaled_width) {
-			fh->width = c.max_scaled_width;
-			btv->init.width = c.max_scaled_width;
-		}
+	bttv_crop_calc_limits(&c);
 
-		if (fh->height < c.min_scaled_height) {
-			fh->height = c.min_scaled_height;
-			btv->init.height = c.min_scaled_height;
-		} else if (fh->height > c.max_scaled_height) {
-			fh->height = c.max_scaled_height;
-			btv->init.height = c.max_scaled_height;
-		}
+	btv->crop[1] = c;
 
-		mutex_unlock(&fh->cap.lock);
+	mutex_unlock(&btv->lock);
 
-		return 0;
-	}
+	fh->do_crop = 1;
 
-	case VIDIOC_ENUMSTD:
-	case VIDIOC_G_STD:
-	case VIDIOC_S_STD:
-	case VIDIOC_ENUMINPUT:
-	case VIDIOC_G_INPUT:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_G_TUNER:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_G_FREQUENCY:
-	case VIDIOC_S_FREQUENCY:
-	case VIDIOC_LOG_STATUS:
-	case VIDIOC_DBG_G_REGISTER:
-	case VIDIOC_DBG_S_REGISTER:
-		return bttv_common_ioctls(btv,cmd,arg);
+	mutex_lock(&fh->cap.lock);
 
-	default:
-		return -ENOIOCTLCMD;
+	if (fh->width < c.min_scaled_width) {
+		fh->width = c.min_scaled_width;
+		btv->init.width = c.min_scaled_width;
+	} else if (fh->width > c.max_scaled_width) {
+		fh->width = c.max_scaled_width;
+		btv->init.width = c.max_scaled_width;
+	}
+
+	if (fh->height < c.min_scaled_height) {
+		fh->height = c.min_scaled_height;
+		btv->init.height = c.min_scaled_height;
+	} else if (fh->height > c.max_scaled_height) {
+		fh->height = c.max_scaled_height;
+		btv->init.height = c.max_scaled_height;
 	}
-	return 0;
 
- fh_unlock_and_return:
 	mutex_unlock(&fh->cap.lock);
-	return retval;
 
- btv_unlock_and_return:
-	mutex_unlock(&btv->lock);
-	return retval;
+	return 0;
 }
 
-static int bttv_ioctl(struct inode *inode, struct file *file,
-		      unsigned int cmd, unsigned long arg)
+static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
-	struct bttv_fh *fh  = file->private_data;
-
-	switch (cmd) {
-	case BTTV_VBISIZE:
-	{
-		const struct bttv_tvnorm *tvnorm;
-
-		tvnorm = fh->vbi_fmt.tvnorm;
-
-		if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
-		    fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
-		    fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
-			/* BTTV_VBISIZE cannot express these parameters,
-			   however open() resets the paramters to defaults
-			   and apps shouldn't call BTTV_VBISIZE after
-			   VIDIOC_S_FMT. */
-			return -EINVAL;
-		}
-
-		bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-		return (fh->vbi_fmt.fmt.count[0] * 2
-			* fh->vbi_fmt.fmt.samples_per_line);
-	}
+	strcpy(a->name, "audio");
+	return 0;
+}
 
-	default:
-		return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
-	}
+static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	return 0;
 }
 
 static ssize_t bttv_read(struct file *file, char __user *data,
@@ -3719,8 +3205,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
 	}
 
 	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == STATE_DONE ||
-	    buf->vb.state == STATE_ERROR)
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
 		return POLLIN|POLLRDNORM;
 	return 0;
 }
@@ -3777,7 +3263,7 @@ static int bttv_open(struct inode *inode, struct file *file)
 			    V4L2_FIELD_SEQ_TB,
 			    sizeof(struct bttv_buffer),
 			    fh);
-	i2c_vidiocschan(btv);
+	set_tvnorm(btv,btv->tvnorm);
 
 	btv->users++;
 
@@ -3857,7 +3343,7 @@ static const struct file_operations bttv_fops =
 	.owner	  = THIS_MODULE,
 	.open	  = bttv_open,
 	.release  = bttv_release,
-	.ioctl	  = bttv_ioctl,
+	.ioctl	  = video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek	  = no_llseek,
 	.read	  = bttv_read,
@@ -3867,19 +3353,61 @@ static const struct file_operations bttv_fops =
 
 static struct video_device bttv_video_template =
 {
-	.name     = "UNSET",
-	.type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
-		    VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-	.fops     = &bttv_fops,
-	.minor    = -1,
-};
-
-static struct video_device bttv_vbi_template =
-{
-	.name     = "bt848/878 vbi",
-	.type     = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
 	.fops     = &bttv_fops,
 	.minor    = -1,
+	.vidioc_querycap                = bttv_querycap,
+	.vidioc_enum_fmt_cap            = bttv_enum_fmt_cap,
+	.vidioc_g_fmt_cap               = bttv_g_fmt_cap,
+	.vidioc_try_fmt_cap             = bttv_try_fmt_cap,
+	.vidioc_s_fmt_cap               = bttv_s_fmt_cap,
+	.vidioc_enum_fmt_overlay        = bttv_enum_fmt_overlay,
+	.vidioc_g_fmt_overlay           = bttv_g_fmt_overlay,
+	.vidioc_try_fmt_overlay         = bttv_try_fmt_overlay,
+	.vidioc_s_fmt_overlay           = bttv_s_fmt_overlay,
+	.vidioc_enum_fmt_vbi            = bttv_enum_fmt_vbi,
+	.vidioc_g_fmt_vbi               = bttv_g_fmt_vbi,
+	.vidioc_try_fmt_vbi             = bttv_try_fmt_vbi,
+	.vidioc_s_fmt_vbi               = bttv_s_fmt_vbi,
+	.vidioc_g_audio                 = bttv_g_audio,
+	.vidioc_s_audio                 = bttv_s_audio,
+	.vidioc_cropcap                 = bttv_cropcap,
+	.vidioc_reqbufs                 = bttv_reqbufs,
+	.vidioc_querybuf                = bttv_querybuf,
+	.vidioc_qbuf                    = bttv_qbuf,
+	.vidioc_dqbuf                   = bttv_dqbuf,
+	.vidioc_s_std                   = bttv_s_std,
+	.vidioc_enum_input              = bttv_enum_input,
+	.vidioc_g_input                 = bttv_g_input,
+	.vidioc_s_input                 = bttv_s_input,
+	.vidioc_queryctrl               = bttv_queryctrl,
+	.vidioc_g_ctrl                  = bttv_g_ctrl,
+	.vidioc_s_ctrl                  = bttv_s_ctrl,
+	.vidioc_streamon                = bttv_streamon,
+	.vidioc_streamoff               = bttv_streamoff,
+	.vidioc_g_tuner                 = bttv_g_tuner,
+	.vidioc_s_tuner                 = bttv_s_tuner,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	.vidiocgmbuf                    = vidiocgmbuf,
+#endif
+	.vidioc_g_crop                  = bttv_g_crop,
+	.vidioc_g_crop                  = bttv_g_crop,
+	.vidioc_s_crop                  = bttv_s_crop,
+	.vidioc_g_fbuf                  = bttv_g_fbuf,
+	.vidioc_s_fbuf                  = bttv_s_fbuf,
+	.vidioc_overlay                 = bttv_overlay,
+	.vidioc_g_priority              = bttv_g_priority,
+	.vidioc_s_priority              = bttv_s_priority,
+	.vidioc_g_parm                  = bttv_g_parm,
+	.vidioc_g_frequency             = bttv_g_frequency,
+	.vidioc_s_frequency             = bttv_s_frequency,
+	.vidioc_log_status		= bttv_log_status,
+	.vidioc_querystd		= bttv_querystd,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register		= bttv_g_register,
+	.vidioc_s_register		= bttv_s_register,
+#endif
+	.tvnorms                        = BTTV_NORMS,
+	.current_norm                   = V4L2_STD_PAL,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -3918,7 +3446,7 @@ static int radio_open(struct inode *inode, struct file *file)
 
 static int radio_release(struct inode *inode, struct file *file)
 {
-	struct bttv        *btv = file->private_data;
+	struct bttv *btv = file->private_data;
 	struct rds_command cmd;
 
 	btv->radio_user--;
@@ -3928,59 +3456,116 @@ static int radio_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static int radio_do_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, void *arg)
+static int radio_querycap(struct file *file, void *priv,
+					struct v4l2_capability *cap)
 {
-	struct bttv    *btv = file->private_data;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-	switch (cmd) {
-	case VIDIOCGCAP:
-	{
-		struct video_capability *cap = arg;
+	strcpy(cap->driver, "bttv");
+	strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
+	cap->version = BTTV_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_TUNER;
 
-		memset(cap,0,sizeof(*cap));
-		strcpy(cap->name,btv->radio_dev->name);
-		cap->type = VID_TYPE_TUNER;
-		cap->channels = 1;
-		cap->audios = 1;
-		return 0;
-	}
+	return 0;
+}
 
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner *v = arg;
+static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-		if(v->tuner)
-			return -EINVAL;
-		memset(v,0,sizeof(*v));
-		strcpy(v->name, "Radio");
-		bttv_call_i2c_clients(btv,cmd,v);
-		return 0;
-	}
-	case VIDIOCSTUNER:
-		/* nothing to do */
-		return 0;
+	if (UNSET == bttv_tvcards[btv->c.type].tuner)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+	mutex_lock(&btv->lock);
+	memset(t, 0, sizeof(*t));
+	strcpy(t->name, "Radio");
+	t->type = V4L2_TUNER_RADIO;
 
-	case BTTV_VERSION:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-	case VIDIOC_LOG_STATUS:
-	case VIDIOC_DBG_G_REGISTER:
-	case VIDIOC_DBG_S_REGISTER:
-		return bttv_common_ioctls(btv,cmd,arg);
+	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+
+	if (btv->audio_mode_gpio)
+		btv->audio_mode_gpio(btv, t, 0);
+
+	mutex_unlock(&btv->lock);
+
+	return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+
+	strcpy(i->name, "Radio");
+	 i->type = V4L2_INPUT_TYPE_TUNER;
+
+	return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	memset(a, 0, sizeof(*a));
+	strcpy(a->name, "Radio");
+	return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+	return 0;
+}
+
+static int radio_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	return 0;
+}
+
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	return 0;
+}
+
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	const struct v4l2_queryctrl *ctrl;
+
+	if (c->id <  V4L2_CID_BASE ||
+			c->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+
+	if (c->id == V4L2_CID_AUDIO_MUTE) {
+		ctrl = ctrl_by_id(c->id);
+		*c = *ctrl;
+	} else
+		*c = no_ctl;
 
-	default:
-		return -ENOIOCTLCMD;
-	}
 	return 0;
 }
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg)
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
 {
-	return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
+	*i = 0;
+	return 0;
 }
 
 static ssize_t radio_read(struct file *file, char __user *data,
@@ -4016,17 +3601,29 @@ static const struct file_operations radio_fops =
 	.open	  = radio_open,
 	.read     = radio_read,
 	.release  = radio_release,
-	.ioctl	  = radio_ioctl,
+	.ioctl	  = video_ioctl2,
 	.llseek	  = no_llseek,
 	.poll     = radio_poll,
 };
 
 static struct video_device radio_template =
 {
-	.name     = "bt848/878 radio",
-	.type     = VID_TYPE_TUNER,
 	.fops     = &radio_fops,
 	.minor    = -1,
+	.vidioc_querycap        = radio_querycap,
+	.vidioc_g_tuner         = radio_g_tuner,
+	.vidioc_enum_input      = radio_enum_input,
+	.vidioc_g_audio         = radio_g_audio,
+	.vidioc_s_tuner         = radio_s_tuner,
+	.vidioc_s_audio         = radio_s_audio,
+	.vidioc_s_input         = radio_s_input,
+	.vidioc_s_std           = radio_s_std,
+	.vidioc_queryctrl       = radio_queryctrl,
+	.vidioc_g_input         = radio_g_input,
+	.vidioc_g_ctrl          = bttv_g_ctrl,
+	.vidioc_s_ctrl          = bttv_s_ctrl,
+	.vidioc_g_frequency     = bttv_g_frequency,
+	.vidioc_s_frequency     = bttv_s_frequency,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -4308,20 +3905,20 @@ static void bttv_irq_timeout(unsigned long data)
 	bttv_set_dma(btv, 0);
 
 	/* wake up */
-	bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
-	bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
+	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR);
+	bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR);
 
 	/* cancel all outstanding capture / vbi requests */
 	while (!list_empty(&btv->capture)) {
 		item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
 		list_del(&item->vb.queue);
-		item->vb.state = STATE_ERROR;
+		item->vb.state = VIDEOBUF_ERROR;
 		wake_up(&item->vb.done);
 	}
 	while (!list_empty(&btv->vcapture)) {
 		item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
 		list_del(&item->vb.queue);
-		item->vb.state = STATE_ERROR;
+		item->vb.state = VIDEOBUF_ERROR;
 		wake_up(&item->vb.done);
 	}
 
@@ -4344,7 +3941,7 @@ bttv_irq_wakeup_top(struct bttv *btv)
 
 	do_gettimeofday(&wakeup->vb.ts);
 	wakeup->vb.field_count = btv->field_count;
-	wakeup->vb.state = STATE_DONE;
+	wakeup->vb.state = VIDEOBUF_DONE;
 	wake_up(&wakeup->vb.done);
 	spin_unlock(&btv->s_lock);
 }
@@ -4393,7 +3990,7 @@ bttv_irq_switch_video(struct bttv *btv)
 	}
 
 	/* wake up finished buffers */
-	bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
+	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE);
 	spin_unlock(&btv->s_lock);
 }
 
@@ -4426,7 +4023,7 @@ bttv_irq_switch_vbi(struct bttv *btv)
 	bttv_buffer_activate_vbi(btv, new);
 	bttv_set_dma(btv, 0);
 
-	bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
+	bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE);
 	spin_unlock(&btv->s_lock);
 }
 
@@ -4548,8 +4145,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
 /* initialitation                                                          */
 
 static struct video_device *vdev_init(struct bttv *btv,
-				      struct video_device *template,
-				      char *type)
+				      const struct video_device *template,
+				      const char *type_name,
+				      const int type)
 {
 	struct video_device *vfd;
 
@@ -4560,9 +4158,10 @@ static struct video_device *vdev_init(struct bttv *btv,
 	vfd->minor   = -1;
 	vfd->dev     = &btv->c.pci->dev;
 	vfd->release = video_device_release;
+	vfd->type    = type;
 	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
 		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
-		 type, bttv_tvcards[btv->c.type].name);
+		 type_name, bttv_tvcards[btv->c.type].name);
 	return vfd;
 }
 
@@ -4594,6 +4193,11 @@ static void bttv_unregister_video(struct bttv *btv)
 /* register video4linux devices */
 static int __devinit bttv_register_video(struct bttv *btv)
 {
+	int video_type = VID_TYPE_CAPTURE |
+			 VID_TYPE_TUNER   |
+			 VID_TYPE_CLIPPING|
+			 VID_TYPE_SCALES;
+
 	if (no_overlay <= 0) {
 		bttv_video_template.type |= VID_TYPE_OVERLAY;
 	} else {
@@ -4601,7 +4205,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
 	}
 
 	/* video */
-	btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
+	btv->video_dev = vdev_init(btv, &bttv_video_template,
+				   "video", video_type);
+
 	if (NULL == btv->video_dev)
 		goto err;
 	if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
@@ -4616,7 +4222,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
 	}
 
 	/* vbi */
-	btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
+	btv->vbi_dev = vdev_init(btv, &bttv_video_template,
+				 "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT);
+
 	if (NULL == btv->vbi_dev)
 		goto err;
 	if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
@@ -4627,7 +4235,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
 	if (!btv->has_radio)
 		return 0;
 	/* radio */
-	btv->radio_dev = vdev_init(btv, &radio_template, "radio");
+	btv->radio_dev = vdev_init(btv, &radio_template,
+				   "radio", VID_TYPE_TUNER);
 	if (NULL == btv->radio_dev)
 		goto err;
 	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
@@ -4768,7 +4377,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 	btv->init.btv         = btv;
 	btv->init.ov.w.width  = 320;
 	btv->init.ov.w.height = 240;
-	btv->init.fmt         = format_by_palette(VIDEO_PALETTE_RGB24);
+	btv->init.fmt         = format_by_fourcc(V4L2_PIX_FMT_BGR24);
 	btv->init.width       = 320;
 	btv->init.height      = 240;
 	btv->input = 0;
@@ -5013,14 +4622,17 @@ static int __init bttv_init_module(void)
 		printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
 		return ret;
 	}
-	return pci_register_driver(&bttv_pci_driver);
+	ret = pci_register_driver(&bttv_pci_driver);
+	if (ret < 0)
+		bus_unregister(&bttv_sub_bus_type);
+
+	return ret;
 }
 
 static void __exit bttv_cleanup_module(void)
 {
 	pci_unregister_driver(&bttv_pci_driver);
 	bus_unregister(&bttv_sub_bus_type);
-	return;
 }
 
 module_init(bttv_init_module);

+ 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;

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác