浏览代码

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb

* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (310 commits)
  V4L/DVB (6316): Change list_for_each+list_entry to list_for_each_entry
  V4L/DVB (6315): pvrusb2: Change list_for_each+list_entry to list_for_each_entry
  V4L/DVB (6314): saa7134: Replace list_for_each+list_entry with list_for_each_entry
  V4L/DVB (6313): ivtv: Replace list_for_each+list_entry with list_for_each_entry
  V4L/DVB (6312): cx88: Replace list_for_each+list_entry with list_for_each_entry
  V4L/DVB (6311): dvb: Replace list_for_each+list_entry with list_for_each_entry
  V4L/DVB (6308): V4L: zc0301, remove bad usage of ERESTARTSYS
  V4L/DVB (6307): V4L: w9968cf, remove bad usage of ERESTARTSYS
  V4L/DVB (6306): Few clenups for saa7134 resume code
  V4L/DVB (6305): V4L: videobuf-core.c avoid NULL dereferences in videobuf-core
  V4L/DVB (6301): pvrusb: Update DEBUGIFC sysfs to kernel 2.6.13+
  V4L/DVB (6300): CodingStyle cleanup
  V4L/DVB (6299): dvb: Add dependencies for VIDEOBUF_DVB
  V4L/DVB (6297): cx23885: remove wrong Kconfig selection of VIDEOBUF
  V4L/DVB (6296): dib0700: add support for AverMedia DVB-T Express card
  V4L/DVB (6295): saa7134: add autodetection for KWorld ATSC-115
  V4L/DVB (6293): V4L: convert struct class_device to struct device
  V4L/DVB (6292): videobuf_core init always require callback implementation
  V4L/DVB (6291): Fix: avoid oops on some SMP machines
  V4L/DVB (6290): remove videobuf_set_pci_ops
  ...
Linus Torvalds 17 年之前
父节点
当前提交
c634920aba
共有 100 个文件被更改,包括 5317 次插入1264 次删除
  1. 1 1
      Documentation/dvb/faq.txt
  2. 1 0
      Documentation/video4linux/CARDLIST.bttv
  3. 5 0
      Documentation/video4linux/CARDLIST.cx23885
  4. 3 2
      Documentation/video4linux/CARDLIST.saa7134
  5. 68 2
      drivers/media/Kconfig
  6. 1 1
      drivers/media/common/Kconfig
  7. 0 1
      drivers/media/common/ir-functions.c
  8. 61 1
      drivers/media/common/ir-keymaps.c
  9. 14 20
      drivers/media/common/saa7146_core.c
  10. 3 2
      drivers/media/common/saa7146_fops.c
  11. 17 6
      drivers/media/common/saa7146_i2c.c
  12. 6 3
      drivers/media/common/saa7146_vbi.c
  13. 7 4
      drivers/media/common/saa7146_video.c
  14. 0 1
      drivers/media/dvb/bt8xx/bt878.c
  15. 3 4
      drivers/media/dvb/bt8xx/bt878.h
  16. 0 1
      drivers/media/dvb/bt8xx/dvb-bt8xx.c
  17. 5 3
      drivers/media/dvb/cinergyT2/cinergyT2.c
  18. 0 1
      drivers/media/dvb/dvb-core/dmxdev.c
  19. 21 72
      drivers/media/dvb/dvb-core/dvb_ca_en50221.c
  20. 1 4
      drivers/media/dvb/dvb-core/dvb_demux.c
  21. 97 28
      drivers/media/dvb/dvb-core/dvb_frontend.c
  22. 12 1
      drivers/media/dvb/dvb-core/dvb_frontend.h
  23. 4 18
      drivers/media/dvb/dvb-core/dvb_net.c
  24. 14 27
      drivers/media/dvb/dvb-core/dvbdev.c
  25. 2 0
      drivers/media/dvb/dvb-usb/Kconfig
  26. 3 2
      drivers/media/dvb/dvb-usb/dib0700.h
  27. 21 2
      drivers/media/dvb/dvb-usb/dib0700_core.c
  28. 665 11
      drivers/media/dvb/dvb-usb/dib0700_devices.c
  29. 25 3
      drivers/media/dvb/dvb-usb/dtt200u.c
  30. 20 6
      drivers/media/dvb/dvb-usb/dvb-usb-ids.h
  31. 1 1
      drivers/media/dvb/dvb-usb/dvb-usb-init.c
  32. 51 33
      drivers/media/dvb/dvb-usb/gp8psk-fe.c
  33. 71 22
      drivers/media/dvb/dvb-usb/gp8psk.c
  34. 25 7
      drivers/media/dvb/dvb-usb/gp8psk.h
  35. 1 1
      drivers/media/dvb/dvb-usb/vp7045.c
  36. 32 1
      drivers/media/dvb/frontends/Kconfig
  37. 4 0
      drivers/media/dvb/frontends/Makefile
  38. 0 1
      drivers/media/dvb/frontends/bcm3510.c
  39. 0 1
      drivers/media/dvb/frontends/cx22700.c
  40. 0 1
      drivers/media/dvb/frontends/cx24110.c
  41. 0 1
      drivers/media/dvb/frontends/cx24123.c
  42. 580 0
      drivers/media/dvb/frontends/dib0070.c
  43. 44 0
      drivers/media/dvb/frontends/dib0070.h
  44. 0 1
      drivers/media/dvb/frontends/dib3000mb.c
  45. 121 71
      drivers/media/dvb/frontends/dib3000mc.c
  46. 451 246
      drivers/media/dvb/frontends/dib7000m.c
  47. 614 253
      drivers/media/dvb/frontends/dib7000p.c
  48. 7 7
      drivers/media/dvb/frontends/dib7000p.h
  49. 10 47
      drivers/media/dvb/frontends/dibx000_common.h
  50. 110 37
      drivers/media/dvb/frontends/dvb-pll.c
  51. 0 1
      drivers/media/dvb/frontends/dvb_dummy_fe.c
  52. 0 1
      drivers/media/dvb/frontends/isl6421.c
  53. 0 1
      drivers/media/dvb/frontends/l64781.c
  54. 0 1
      drivers/media/dvb/frontends/lgdt330x.c
  55. 0 1
      drivers/media/dvb/frontends/lnbp21.c
  56. 0 1
      drivers/media/dvb/frontends/mt2060.c
  57. 314 0
      drivers/media/dvb/frontends/mt2131.c
  58. 54 0
      drivers/media/dvb/frontends/mt2131.h
  59. 49 0
      drivers/media/dvb/frontends/mt2131_priv.h
  60. 287 0
      drivers/media/dvb/frontends/mt2266.c
  61. 37 0
      drivers/media/dvb/frontends/mt2266.h
  62. 0 1
      drivers/media/dvb/frontends/mt312.c
  63. 0 1
      drivers/media/dvb/frontends/mt352.c
  64. 0 1
      drivers/media/dvb/frontends/nxt200x.c
  65. 0 1
      drivers/media/dvb/frontends/or51132.c
  66. 0 1
      drivers/media/dvb/frontends/or51211.c
  67. 729 0
      drivers/media/dvb/frontends/s5h1409.c
  68. 73 0
      drivers/media/dvb/frontends/s5h1409.h
  69. 0 1
      drivers/media/dvb/frontends/sp8870.c
  70. 0 1
      drivers/media/dvb/frontends/sp887x.c
  71. 2 2
      drivers/media/dvb/frontends/stv0297.c
  72. 0 1
      drivers/media/dvb/frontends/stv0299.c
  73. 2 2
      drivers/media/dvb/frontends/tda10021.c
  74. 2 8
      drivers/media/dvb/frontends/tda10023.c
  75. 0 1
      drivers/media/dvb/frontends/tda1004x.c
  76. 0 1
      drivers/media/dvb/frontends/tda10086.c
  77. 4 5
      drivers/media/dvb/frontends/tda8083.c
  78. 2 2
      drivers/media/dvb/frontends/ves1820.c
  79. 0 1
      drivers/media/dvb/frontends/zl10353.c
  80. 1 2
      drivers/media/dvb/ttpci/av7110.c
  81. 14 14
      drivers/media/dvb/ttpci/av7110_hw.c
  82. 1 2
      drivers/media/dvb/ttpci/av7110_ir.c
  83. 4 2
      drivers/media/dvb/ttpci/av7110_v4l.c
  84. 1 1
      drivers/media/dvb/ttpci/budget-av.c
  85. 1 1
      drivers/media/dvb/ttpci/budget-ci.c
  86. 0 1
      drivers/media/dvb/ttpci/budget-core.c
  87. 0 1
      drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
  88. 0 1
      drivers/media/dvb/ttusb-dec/ttusb_dec.c
  89. 20 4
      drivers/media/radio/Kconfig
  90. 429 189
      drivers/media/radio/radio-gemtek.c
  91. 1 1
      drivers/media/radio/radio-terratec.c
  92. 19 10
      drivers/media/video/Kconfig
  93. 20 8
      drivers/media/video/Makefile
  94. 1 2
      drivers/media/video/arv.c
  95. 1 1
      drivers/media/video/bt8xx/Kconfig
  96. 27 11
      drivers/media/video/bt8xx/bttv-cards.c
  97. 18 13
      drivers/media/video/bt8xx/bttv-driver.c
  98. 2 4
      drivers/media/video/bt8xx/bttv-gpio.c
  99. 0 1
      drivers/media/video/bt8xx/bttv-i2c.c
  100. 0 1
      drivers/media/video/bt8xx/bttv-input.c

+ 1 - 1
Documentation/dvb/faq.txt

@@ -150,7 +150,7 @@ Some very frequently asked questions about linuxtv-dvb
 	- saa7146_vv: SAA7146 video and vbi functions. These are only needed
 	  for full-featured cards.
 
-	- video-buf: capture helper module for the saa7146_vv driver. This
+	- videobuf-dma-sg: capture helper module for the saa7146_vv driver. This
 	  one is responsible to handle capture buffers.
 
 	- dvb-ttpci: The main driver for AV7110 based, full-featured

+ 1 - 0
Documentation/video4linux/CARDLIST.bttv

@@ -147,3 +147,4 @@
 146 -> SSAI Ultrasound Video Interface                     [414a:5353]
 147 -> VoodooTV 200 (USA)                                  [121a:3000]
 148 -> DViCO FusionHDTV 2                                  [dbc0:d200]
+149 -> Typhoon TV-Tuner PCI (50684)

+ 5 - 0
Documentation/video4linux/CARDLIST.cx23885

@@ -0,0 +1,5 @@
+  0 -> UNKNOWN/GENERIC                                     [0070:3400]
+  1 -> Hauppauge WinTV-HVR1800lp                           [0070:7600]
+  2 -> Hauppauge WinTV-HVR1800                             [0070:7800,0070:7801]
+  3 -> Hauppauge WinTV-HVR1250                             [0070:7911]
+  4 -> DViCO FusionHDTV5 Express                           [18ac:d500]

+ 3 - 2
Documentation/video4linux/CARDLIST.saa7134

@@ -88,11 +88,11 @@
  87 -> ADS Instant TV Duo Cardbus PTV331        [0331:1421]
  88 -> Tevion/KWorld DVB-T 220RF                [17de:7201]
  89 -> ELSA EX-VISION 700TV                     [1048:226c]
- 90 -> Kworld ATSC110                           [17de:7350]
+ 90 -> Kworld ATSC110/115                       [17de:7350,17de:7352]
  91 -> AVerMedia A169 B                         [1461:7360]
  92 -> AVerMedia A169 B1                        [1461:6360]
  93 -> Medion 7134 Bridge #2                    [16be:0005]
- 94 -> LifeView FlyDVB-T Hybrid Cardbus         [5168:3306,5168:3502]
+ 94 -> LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB [5168:3306,5168:3502,4e42:3502]
  95 -> LifeView FlyVIDEO3000 (NTSC)             [5169:0138]
  96 -> Medion Md8800 Quadro                     [16be:0007,16be:0008]
  97 -> LifeView FlyDVB-S /Acorp TV134DS         [5168:0300,4e42:0300]
@@ -115,3 +115,4 @@
 114 -> KWorld DVB-T 210                         [17de:7250]
 115 -> Sabrent PCMCIA TV-PCB05                  [0919:2003]
 116 -> 10MOONS TM300 TV Card                    [1131:2304]
+117 -> Avermedia Super 007                      [1461:f01d]

+ 68 - 2
drivers/media/Kconfig

@@ -69,13 +69,79 @@ source "drivers/media/common/Kconfig"
 config VIDEO_TUNER
 	tristate
 	depends on I2C
+	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
+
+menuconfig VIDEO_TUNER_CUSTOMIZE
+	bool "Customize analog tuner modules to build"
+	depends on VIDEO_TUNER
+	help
+	  This allows the user to deselect tuner drivers unnecessary
+	  for their hardware from the build. Use this option with care
+	  as deselecting tuner drivers which are in fact necessary will
+	  result in V4L devices which cannot be tuned due to lack of
+	  driver support
+
+	  If unsure say N.
+
+if VIDEO_TUNER_CUSTOMIZE
+
+config TUNER_MT20XX
+	tristate "Microtune 2032 / 2050 tuners"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for the MT2032 / MT2050 tuner.
+
+config TUNER_TDA8290
+	tristate "TDA 8290+8275(a) tuner combo"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for Philips TDA8290+8275(a) tuner.
+
+config TUNER_TEA5761
+	tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
+	depends on I2C && EXPERIMENTAL
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for the Philips TEA5761 radio tuner.
+
+config TUNER_TEA5767
+	tristate "TEA 5767 radio tuner"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for the Philips TEA5767 radio tuner.
+
+config TUNER_SIMPLE
+	tristate "Simple tuner support"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for various simple tuners.
 
-config VIDEO_BUF
+endif # VIDEO_TUNER_CUSTOMIZE
+
+config VIDEOBUF_GEN
+	tristate
+
+config VIDEOBUF_DMA_SG
 	depends on PCI
+	select VIDEOBUF_GEN
+	tristate
+
+config VIDEOBUF_VMALLOC
+	select VIDEOBUF_GEN
 	tristate
 
-config VIDEO_BUF_DVB
+config VIDEOBUF_DVB
 	tristate
+	select VIDEOBUF_GEN
+	select VIDEOBUF_DMA_SG
 
 config VIDEO_BTCX
 	tristate

+ 1 - 1
drivers/media/common/Kconfig

@@ -5,5 +5,5 @@ config VIDEO_SAA7146
 config VIDEO_SAA7146_VV
 	tristate
 	depends on VIDEO_DEV
-	select VIDEO_BUF
+	select VIDEOBUF_DMA_SG
 	select VIDEO_SAA7146

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

@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/jiffies.h>
 #include <media/ir-common.h>

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

@@ -20,7 +20,6 @@
 
  */
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 
 #include <linux/input.h>
 #include <media/ir-common.h>
@@ -1783,3 +1782,64 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
+
+/* DViCO FUSION HDTV MCE remote */
+IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
+
+	[ 0x0b ] = KEY_1,
+	[ 0x17 ] = KEY_2,
+	[ 0x1b ] = KEY_3,
+	[ 0x07 ] = KEY_4,
+	[ 0x50 ] = KEY_5,
+	[ 0x54 ] = KEY_6,
+	[ 0x48 ] = KEY_7,
+	[ 0x4c ] = KEY_8,
+	[ 0x58 ] = KEY_9,
+	[ 0x03 ] = KEY_0,
+
+	[ 0x5e ] = KEY_OK,
+	[ 0x51 ] = KEY_UP,
+	[ 0x53 ] = KEY_DOWN,
+	[ 0x5b ] = KEY_LEFT,
+	[ 0x5f ] = KEY_RIGHT,
+
+	[ 0x02 ] = KEY_TV,		/* Labeled DTV on remote */
+	[ 0x0e ] = KEY_MP3,
+	[ 0x1a ] = KEY_DVD,
+	[ 0x1e ] = KEY_FAVORITES,	/* Labeled CPF on remote */
+	[ 0x16 ] = KEY_SETUP,
+	[ 0x46 ] = KEY_POWER2,		/* TV On/Off button on remote */
+	[ 0x0a ] = KEY_EPG,		/* Labeled Guide on remote */
+
+	[ 0x49 ] = KEY_BACK,
+	[ 0x59 ] = KEY_INFO,		/* Labeled MORE on remote */
+	[ 0x4d ] = KEY_MENU,		/* Labeled DVDMENU on remote */
+	[ 0x55 ] = KEY_CYCLEWINDOWS,	/* Labeled ALT-TAB on remote */
+
+	[ 0x0f ] = KEY_PREVIOUSSONG,	/* Labeled |<< REPLAY on remote */
+	[ 0x12 ] = KEY_NEXTSONG,	/* Labeled >>| SKIP on remote */
+	[ 0x42 ] = KEY_ENTER, 		/* Labeled START with a green
+					 * MS windows logo on remote */
+
+	[ 0x15 ] = KEY_VOLUMEUP,
+	[ 0x05 ] = KEY_VOLUMEDOWN,
+	[ 0x11 ] = KEY_CHANNELUP,
+	[ 0x09 ] = KEY_CHANNELDOWN,
+
+	[ 0x52 ] = KEY_CAMERA,
+	[ 0x5a ] = KEY_TUNER,
+	[ 0x19 ] = KEY_OPEN,
+
+	[ 0x13 ] = KEY_MODE,		/* 4:3 16:9 select */
+	[ 0x1f ] = KEY_ZOOM,
+
+	[ 0x43 ] = KEY_REWIND,
+	[ 0x47 ] = KEY_PLAYPAUSE,
+	[ 0x4f ] = KEY_FASTFORWARD,
+	[ 0x57 ] = KEY_MUTE,
+	[ 0x0d ] = KEY_STOP,
+	[ 0x01 ] = KEY_RECORD,
+	[ 0x4e ] = KEY_POWER,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);

+ 14 - 20
drivers/media/common/saa7146_core.c

@@ -100,7 +100,7 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
  * general helper functions
  ****************************************************************************/
 
-/* this is videobuf_vmalloc_to_sg() from video-buf.c
+/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
    make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
    may be triggered on highmem machines */
 static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
@@ -248,10 +248,11 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
 static irqreturn_t interrupt_hw(int irq, void *dev_id)
 {
 	struct saa7146_dev *dev = dev_id;
-	u32 isr = 0;
+	u32 isr;
+	u32 ack_isr;
 
 	/* read out the interrupt status register */
-	isr = saa7146_read(dev, ISR);
+	ack_isr = isr = saa7146_read(dev, ISR);
 
 	/* is this our interrupt? */
 	if ( 0 == isr ) {
@@ -259,8 +260,6 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
 		return IRQ_NONE;
 	}
 
-	saa7146_write(dev, ISR, isr);
-
 	if( 0 != (dev->ext)) {
 		if( 0 != (dev->ext->irq_mask & isr )) {
 			if( 0 != dev->ext->irq_func ) {
@@ -283,21 +282,16 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
 		isr &= ~MASK_28;
 	}
 	if (0 != (isr & (MASK_16|MASK_17))) {
-		u32 status = saa7146_read(dev, I2C_STATUS);
-		if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) {
-			SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
-			/* only wake up if we expect something */
-			if( 0 != dev->i2c_op ) {
-				u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2;
-				u32 ssr = (saa7146_read(dev, SSR) >> 17) & 0x1f;
-				DEB_I2C(("irq: i2c, status: 0x%08x, psr:0x%02x, ssr:0x%02x).\n",status,psr,ssr));
-				dev->i2c_op = 0;
-				wake_up(&dev->i2c_wq);
-			} else {
-				DEB_I2C(("unexpected irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
-			}
+		SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+		/* only wake up if we expect something */
+		if (0 != dev->i2c_op) {
+			dev->i2c_op = 0;
+			wake_up(&dev->i2c_wq);
 		} else {
-			DEB_I2C(("unhandled irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
+			u32 psr = saa7146_read(dev, PSR);
+			u32 ssr = saa7146_read(dev, SSR);
+			printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
+			       dev->name, isr, psr, ssr);
 		}
 		isr &= ~(MASK_16|MASK_17);
 	}
@@ -306,6 +300,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
 		ERR(("disabling interrupt source(s)!\n"));
 		SAA7146_IER_DISABLE(dev,isr);
 	}
+	saa7146_write(dev, ISR, ack_isr);
 	return IRQ_HANDLED;
 }
 
@@ -548,7 +543,6 @@ EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
 
 EXPORT_SYMBOL_GPL(saa7146_setgpio);
 
-EXPORT_SYMBOL_GPL(saa7146_i2c_transfer);
 EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
 
 EXPORT_SYMBOL_GPL(saa7146_debug);

+ 3 - 2
drivers/media/common/saa7146_fops.c

@@ -53,13 +53,14 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
 void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
 						struct saa7146_buf *buf)
 {
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 	DEB_EE(("dev:%p, buf:%p\n",dev,buf));
 
 	BUG_ON(in_interrupt());
 
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(q, &buf->vb.dma);
-	videobuf_dma_free(&buf->vb.dma);
+	videobuf_dma_unmap(q, dma);
+	videobuf_dma_free(dma);
 	buf->vb.state = STATE_NEEDS_INIT;
 }
 

+ 17 - 6
drivers/media/common/saa7146_i2c.c

@@ -202,7 +202,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
 				/* a signal arrived */
 				return -ERESTARTSYS;
 
-			printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for end of xfer\n");
+			printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n",
+				dev->name, __FUNCTION__);
 			return -EIO;
 		}
 		status = saa7146_read(dev, I2C_STATUS);
@@ -219,7 +220,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
 				break;
 			}
 			if (time_after(jiffies,timeout)) {
-				printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for MC2\n");
+				printk(KERN_WARNING "%s %s: timed out waiting for MC2\n",
+					dev->name, __FUNCTION__);
 				return -EIO;
 			}
 		}
@@ -235,7 +237,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
 				/* this is normal when probing the bus
 				 * (no answer from nonexisistant device...)
 				 */
-				DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n"));
+				printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n",
+					dev->name, __FUNCTION__);
 				return -EIO;
 			}
 			if (++trial < 50 && short_delay)
@@ -246,8 +249,16 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
 	}
 
 	/* give a detailed status report */
-	if ( 0 != (status & SAA7146_I2C_ERR)) {
-
+	if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
+			     SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
+			     SAA7146_I2C_AL    | SAA7146_I2C_ERR   |
+			     SAA7146_I2C_BUSY)) ) {
+
+		if ( 0 == (status & SAA7146_I2C_ERR) ||
+		     0 == (status & SAA7146_I2C_BUSY) ) {
+			/* it may take some time until ERR goes high - ignore */
+			DEB_I2C(("unexpected i2c status %04x\n", status));
+		}
 		if( 0 != (status & SAA7146_I2C_SPERR) ) {
 			DEB_I2C(("error due to invalid start/stop condition.\n"));
 		}
@@ -277,7 +288,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
 	return 0;
 }
 
-int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
+static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
 {
 	int i = 0, count = 0;
 	u32* buffer = dev->d_i2c.cpu_addr;

+ 6 - 3
drivers/media/common/saa7146_vbi.c

@@ -165,7 +165,7 @@ static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf
 	/* we don't wait here for the first field anymore. this is different from the video
 	   capture and might cause that the first buffer is only half filled (with only
 	   one field). but since this is some sort of streaming data, this is not that negative.
-	   but by doing this, we can use the whole engine from video-buf.c... */
+	   but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
 
 /*
 	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
@@ -239,6 +239,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
 		saa7146_dma_free(dev,q,buf);
 
 	if (STATE_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
 		buf->vb.width  = llength;
 		buf->vb.height = lines;
 		buf->vb.size   = size;
@@ -250,7 +252,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
 		err = videobuf_iolock(q,&buf->vb, NULL);
 		if (err)
 			goto oops;
-		err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen);
+		err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
+						 dma->sglist, dma->sglen);
 		if (0 != err)
 			return err;
 	}
@@ -404,7 +407,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
 	fh->vbi_fmt.start[1] = 312;
 	fh->vbi_fmt.count[1] = 16;
 
-	videobuf_queue_init(&fh->vbi_q, &vbi_qops,
+	videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB, // FIXME: does this really work?

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

@@ -594,8 +594,9 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
 static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
 {
 	struct pci_dev *pci = dev->pci;
-	struct scatterlist *list = buf->vb.dma.sglist;
-	int length = buf->vb.dma.sglen;
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+	struct scatterlist *list = dma->sglist;
+	int length = dma->sglen;
 	struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
 
 	DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
@@ -655,7 +656,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
 
 		/* if we have a user buffer, the first page may not be
 		   aligned to a page boundary. */
-		pt1->offset = buf->vb.dma.sglist->offset;
+		pt1->offset = list->offset;
 		pt2->offset = pt1->offset+o1;
 		pt3->offset = pt1->offset+o2;
 
@@ -1211,6 +1212,8 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
 			mutex_unlock(&q->lock);
 			return err;
 		}
+
+		gbuffers = err;
 		memset(mbuf,0,sizeof(*mbuf));
 		mbuf->frames = gbuffers;
 		mbuf->size   = gbuffers * gbufsize;
@@ -1411,7 +1414,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
 	sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
 	fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
 
-	videobuf_queue_init(&fh->video_q, &video_qops,
+	videobuf_queue_pci_init(&fh->video_q, &video_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,

+ 0 - 1
drivers/media/dvb/bt8xx/bt878.c

@@ -28,7 +28,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <asm/io.h>

+ 3 - 4
drivers/media/dvb/bt8xx/bt878.h

@@ -149,11 +149,10 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
 void bt878_stop(struct bt878 *bt);
 
 #if defined(__powerpc__)	/* big-endian */
-extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
+static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
 {
-	__asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val),
-			     "r"(addr));
-	__asm__ __volatile__("eieio":::"memory");
+	st_le32(addr, val);
+	eieio();
 }
 
 #define bmtwrite(dat,adr)  io_st_le32((adr),(dat))

+ 0 - 1
drivers/media/dvb/bt8xx/dvb-bt8xx.c

@@ -21,7 +21,6 @@
 
 #include <linux/bitops.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/device.h>

+ 5 - 3
drivers/media/dvb/cinergyT2/cinergyT2.c

@@ -548,19 +548,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       unsigned int mask = 0;
+	unsigned int mask = 0;
 
 	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	poll_wait(file, &cinergyt2->poll_wq, wait);
 
-       if (cinergyt2->pending_fe_events != 0)
+	if (cinergyt2->pending_fe_events != 0)
 		mask |= (POLLIN | POLLRDNORM | POLLPRI);
 
 	mutex_unlock(&cinergyt2->sem);
 
-       return mask;
+	return mask;
 }
 
 
@@ -1008,6 +1008,8 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
 	cinergyt2_sleep(cinergyt2, 1);
 	mutex_unlock(&cinergyt2->sem);
 
+	mutex_unlock(&cinergyt2->wq_sem);
+
 	return 0;
 }
 

+ 0 - 1
drivers/media/dvb/dvb-core/dmxdev.c

@@ -24,7 +24,6 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/poll.h>
 #include <linux/ioctl.h>
 #include <linux/wait.h>

+ 21 - 72
drivers/media/dvb/dvb-core/dvb_ca_en50221.c

@@ -32,11 +32,11 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/sched.h>
+#include <linux/kthread.h>
 
 #include "dvb_ca_en50221.h"
 #include "dvb_ringbuffer.h"
@@ -140,13 +140,7 @@ struct dvb_ca_private {
 	wait_queue_head_t wait_queue;
 
 	/* PID of the monitoring thread */
-	pid_t thread_pid;
-
-	/* Wait queue used when shutting thread down */
-	wait_queue_head_t thread_queue;
-
-	/* Flag indicating when thread should exit */
-	unsigned int exit:1;
+	struct task_struct *thread;
 
 	/* Flag indicating if the CA device is open */
 	unsigned int open:1;
@@ -902,27 +896,9 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
 
 	ca->wakeup = 1;
 	mb();
-	wake_up_interruptible(&ca->thread_queue);
+	wake_up_process(ca->thread);
 }
 
-/**
- * Used by the CA thread to determine if an early wakeup is necessary
- *
- * @param ca CA instance.
- */
-static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca)
-{
-	if (ca->wakeup) {
-		ca->wakeup = 0;
-		return 1;
-	}
-	if (ca->exit)
-		return 1;
-
-	return 0;
-}
-
-
 /**
  * Update the delay used by the thread.
  *
@@ -982,7 +958,6 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
 static int dvb_ca_en50221_thread(void *data)
 {
 	struct dvb_ca_private *ca = data;
-	char name[15];
 	int slot;
 	int flags;
 	int status;
@@ -991,28 +966,17 @@ static int dvb_ca_en50221_thread(void *data)
 
 	dprintk("%s\n", __FUNCTION__);
 
-	/* setup kernel thread */
-	snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);
-
-	lock_kernel();
-	daemonize(name);
-	sigfillset(&current->blocked);
-	unlock_kernel();
-
 	/* choose the correct initial delay */
 	dvb_ca_en50221_thread_update_delay(ca);
 
 	/* main loop */
-	while (!ca->exit) {
+	while (!kthread_should_stop()) {
 		/* sleep for a bit */
-		if (!ca->wakeup) {
-			flags = wait_event_interruptible_timeout(ca->thread_queue,
-								 dvb_ca_en50221_thread_should_wakeup(ca),
-								 ca->delay);
-			if ((flags == -ERESTARTSYS) || ca->exit) {
-				/* got signal or quitting */
-				break;
-			}
+		while (!ca->wakeup) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(ca->delay);
+			if (kthread_should_stop())
+				return 0;
 		}
 		ca->wakeup = 0;
 
@@ -1181,10 +1145,6 @@ static int dvb_ca_en50221_thread(void *data)
 		}
 	}
 
-	/* completed */
-	ca->thread_pid = 0;
-	mb();
-	wake_up_interruptible(&ca->thread_queue);
 	return 0;
 }
 
@@ -1536,8 +1496,10 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
 		return -EIO;
 
 	err = dvb_generic_open(inode, file);
-	if (err < 0)
+	if (err < 0) {
+		module_put(ca->pub->owner);
 		return err;
+	}
 
 	for (i = 0; i < ca->slot_count; i++) {
 
@@ -1570,7 +1532,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_ca_private *ca = dvbdev->priv;
-	int err = 0;
+	int err;
 
 	dprintk("%s\n", __FUNCTION__);
 
@@ -1582,7 +1544,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
 
 	module_put(ca->pub->owner);
 
-	return 0;
+	return err;
 }
 
 
@@ -1682,9 +1644,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
 		goto error;
 	}
 	init_waitqueue_head(&ca->wait_queue);
-	ca->thread_pid = 0;
-	init_waitqueue_head(&ca->thread_queue);
-	ca->exit = 0;
 	ca->open = 0;
 	ca->wakeup = 0;
 	ca->next_read_slot = 0;
@@ -1710,14 +1669,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
 	mb();
 
 	/* create a kthread for monitoring this CA device */
-
-	ret = kernel_thread(dvb_ca_en50221_thread, ca, 0);
-
-	if (ret < 0) {
-		printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret);
+	ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
+				 ca->dvbdev->adapter->num, ca->dvbdev->id);
+	if (IS_ERR(ca->thread)) {
+		ret = PTR_ERR(ca->thread);
+		printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
+			ret);
 		goto error;
 	}
-	ca->thread_pid = ret;
 	return 0;
 
 error:
@@ -1748,17 +1707,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
 	dprintk("%s\n", __FUNCTION__);
 
 	/* shutdown the thread if there was one */
-	if (ca->thread_pid) {
-		if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
-			printk("dvb_ca_release adapter %d: thread PID %d already died\n",
-			       ca->dvbdev->adapter->num, ca->thread_pid);
-		} else {
-			ca->exit = 1;
-			mb();
-			dvb_ca_en50221_thread_wakeup(ca);
-			wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0);
-		}
-	}
+	kthread_stop(ca->thread);
 
 	for (i = 0; i < ca->slot_count; i++) {
 		dvb_ca_en50221_slot_shutdown(ca, i);

+ 1 - 4
drivers/media/dvb/dvb-core/dvb_demux.c

@@ -373,13 +373,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
 static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
 {
 	struct dvb_demux_feed *feed;
-	struct list_head *pos, *head = &demux->feed_list;
 	u16 pid = ts_pid(buf);
 	int dvr_done = 0;
 
-	list_for_each(pos, head) {
-		feed = list_entry(pos, struct dvb_demux_feed, list_head);
-
+	list_for_each_entry(feed, &demux->feed_list, list_head) {
 		if ((feed->pid != pid) && (feed->pid != 0x2000))
 			continue;
 

+ 97 - 28
drivers/media/dvb/dvb-core/dvb_frontend.c

@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/list.h>
 #include <linux/freezer.h>
 #include <linux/jiffies.h>
@@ -43,7 +42,7 @@
 #include "dvbdev.h"
 
 static int dvb_frontend_debug;
-static int dvb_shutdown_timeout = 5;
+static int dvb_shutdown_timeout;
 static int dvb_force_auto_inversion;
 static int dvb_override_tune_delay;
 static int dvb_powerdown_on_sleep = 1;
@@ -138,7 +137,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (down_interruptible (&events->sem))
+	if (mutex_lock_interruptible (&events->mtx))
 		return;
 
 	wp = (events->eventw + 1) % MAX_EVENT;
@@ -159,7 +158,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 
 	events->eventw = wp;
 
-	up (&events->sem);
+	mutex_unlock(&events->mtx);
 
 	e->status = status;
 
@@ -197,7 +196,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
 			return ret;
 	}
 
-	if (down_interruptible (&events->sem))
+	if (mutex_lock_interruptible (&events->mtx))
 		return -ERESTARTSYS;
 
 	memcpy (event, &events->events[events->eventr],
@@ -205,7 +204,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
 
 	events->eventr = (events->eventr + 1) % MAX_EVENT;
 
-	up (&events->sem);
+	mutex_unlock(&events->mtx);
 
 	return 0;
 }
@@ -574,10 +573,9 @@ restart:
 			dvb_frontend_swzigzag(fe);
 	}
 
-	if (dvb_shutdown_timeout) {
-		if (dvb_powerdown_on_sleep)
-			if (fe->ops.set_voltage)
-				fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+	if (dvb_powerdown_on_sleep) {
+		if (fe->ops.set_voltage)
+			fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
 		if (fe->ops.tuner_ops.sleep) {
 			fe->ops.tuner_ops.sleep(fe);
 			if (fe->ops.i2c_gate_ctrl)
@@ -697,6 +695,65 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
 	return 0;
 }
 
+static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
+					u32 *freq_min, u32 *freq_max)
+{
+	*freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
+
+	if (fe->ops.info.frequency_max == 0)
+		*freq_max = fe->ops.tuner_ops.info.frequency_max;
+	else if (fe->ops.tuner_ops.info.frequency_max == 0)
+		*freq_max = fe->ops.info.frequency_max;
+	else
+		*freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
+
+	if (*freq_min == 0 || *freq_max == 0)
+		printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",
+		       fe->dvb->num);
+}
+
+static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *parms)
+{
+	u32 freq_min;
+	u32 freq_max;
+
+	/* range check: frequency */
+	dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
+	if ((freq_min && parms->frequency < freq_min) ||
+	    (freq_max && parms->frequency > freq_max)) {
+		printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
+		       fe->dvb->num, parms->frequency, freq_min, freq_max);
+		return -EINVAL;
+	}
+
+	/* range check: symbol rate */
+	if (fe->ops.info.type == FE_QPSK) {
+		if ((fe->ops.info.symbol_rate_min &&
+		     parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
+		    (fe->ops.info.symbol_rate_max &&
+		     parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
+			printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+			       fe->dvb->num, parms->u.qpsk.symbol_rate,
+			       fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+			return -EINVAL;
+		}
+
+	} else if (fe->ops.info.type == FE_QAM) {
+		if ((fe->ops.info.symbol_rate_min &&
+		     parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
+		    (fe->ops.info.symbol_rate_max &&
+		     parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
+			printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+			       fe->dvb->num, parms->u.qam.symbol_rate,
+			       fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, void *parg)
 {
@@ -707,7 +764,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (!fe || fepriv->exit)
+	if (fepriv->exit)
 		return -ENODEV;
 
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
@@ -722,6 +779,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 	case FE_GET_INFO: {
 		struct dvb_frontend_info* info = parg;
 		memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
+		dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);
 
 		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
 		 * do it, it is done for it. */
@@ -883,6 +941,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 	case FE_SET_FRONTEND: {
 		struct dvb_frontend_tune_settings fetunesettings;
 
+		if (dvb_frontend_check_parameters(fe, parg) < 0) {
+			err = -EINVAL;
+			break;
+		}
+
 		memcpy (&fepriv->parameters, parg,
 			sizeof (struct dvb_frontend_parameters));
 
@@ -992,18 +1055,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if ((ret = dvb_generic_open (inode, file)) < 0)
-		return ret;
-
-	if (fe->ops.ts_bus_ctrl) {
-		if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) {
-			dvb_generic_release (inode, file);
+	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+		if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
 			return ret;
-		}
 	}
 
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+	if ((ret = dvb_generic_open (inode, file)) < 0)
+		goto err1;
 
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
 		/* normal tune mode when opened R/W */
 		fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
 		fepriv->tone = -1;
@@ -1011,13 +1071,20 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
 
 		ret = dvb_frontend_start (fe);
 		if (ret)
-			dvb_generic_release (inode, file);
+			goto err2;
 
 		/*  empty event queue */
 		fepriv->events.eventr = fepriv->events.eventw = 0;
 	}
 
 	return ret;
+
+err2:
+	dvb_generic_release(inode, file);
+err1:
+	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
+		fe->ops.ts_bus_ctrl(fe, 0);
+	return ret;
 }
 
 static int dvb_frontend_release(struct inode *inode, struct file *file)
@@ -1032,16 +1099,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
 	if ((file->f_flags & O_ACCMODE) != O_RDONLY)
 		fepriv->release_jiffies = jiffies;
 
-	if (fe->ops.ts_bus_ctrl)
-		fe->ops.ts_bus_ctrl (fe, 0);
-
 	ret = dvb_generic_release (inode, file);
 
-	if (dvbdev->users==-1 && fepriv->exit==1) {
-		fops_put(file->f_op);
-		file->f_op = NULL;
-		wake_up(&dvbdev->wait_queue);
+	if (dvbdev->users == -1) {
+		if (fepriv->exit == 1) {
+			fops_put(file->f_op);
+			file->f_op = NULL;
+			wake_up(&dvbdev->wait_queue);
+		}
+		if (fe->ops.ts_bus_ctrl)
+			fe->ops.ts_bus_ctrl(fe, 0);
 	}
+
 	return ret;
 }
 
@@ -1080,7 +1149,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
 	init_MUTEX (&fepriv->sem);
 	init_waitqueue_head (&fepriv->wait_queue);
 	init_waitqueue_head (&fepriv->events.wait_queue);
-	init_MUTEX (&fepriv->events.sem);
+	mutex_init(&fepriv->events.mtx);
 	fe->dvb = dvb;
 	fepriv->inversion = INVERSION_OFF;
 

+ 12 - 1
drivers/media/dvb/dvb-core/dvb_frontend.h

@@ -35,6 +35,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <linux/dvb/frontend.h>
 
@@ -61,6 +62,13 @@ struct dvb_tuner_info {
 	u32 bandwidth_step;
 };
 
+struct analog_parameters {
+	unsigned int frequency;
+	unsigned int mode;
+	unsigned int audmode;
+	u64 std;
+};
+
 struct dvb_tuner_ops {
 
 	struct dvb_tuner_info info;
@@ -71,6 +79,7 @@ struct dvb_tuner_ops {
 
 	/** This is for simple PLLs - set all parameters in one go. */
 	int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+	int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
 
 	/** 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);
@@ -79,7 +88,9 @@ struct dvb_tuner_ops {
 	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
 
 #define TUNER_STATUS_LOCKED 1
+#define TUNER_STATUS_STEREO 2
 	int (*get_status)(struct dvb_frontend *fe, u32 *status);
+	int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
 
 	/** These are provided seperately from set_params in order to facilitate silicon
 	 * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
@@ -142,7 +153,7 @@ struct dvb_fe_events {
 	int			  eventr;
 	int			  overflow;
 	wait_queue_head_t	  wait_queue;
-	struct semaphore	  sem;
+	struct mutex		  mtx;
 };
 
 struct dvb_frontend {

+ 4 - 18
drivers/media/dvb/dvb-core/dvb_net.c

@@ -357,11 +357,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 	static unsigned char *ule_where = ule_hist, ule_dump = 0;
 #endif
 
-	if (dev == NULL) {
-		printk( KERN_ERR "NO netdev struct!\n" );
-		return;
-	}
-
 	/* For all TS cells in current buffer.
 	 * Appearently, we are called for every single TS cell.
 	 */
@@ -800,8 +795,8 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
 }
 
 
-static void dvb_net_sec(struct net_device *dev, const u8 *pkt, int
-pkt_len)
+static void dvb_net_sec(struct net_device *dev,
+			const u8 *pkt, int pkt_len)
 {
 	u8 *eth;
 	struct sk_buff *skb;
@@ -1446,18 +1441,9 @@ static int dvb_net_close(struct inode *inode, struct file *file)
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_net *dvbnet = dvbdev->priv;
 
-	if (!dvbdev)
-		return -ENODEV;
-
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		dvbdev->readers++;
-	} else {
-		dvbdev->writers++;
-	}
-
-	dvbdev->users++;
+	dvb_generic_release(inode, file);
 
-	if(dvbdev->users == 1 && dvbnet->exit==1) {
+	if(dvbdev->users == 1 && dvbnet->exit == 1) {
 		fops_put(file->f_op);
 		file->f_op = NULL;
 		wake_up(&dvbdev->wait_queue);

+ 14 - 27
drivers/media/dvb/dvb-core/dvbdev.c

@@ -25,7 +25,6 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -59,18 +58,13 @@ static struct class *dvb_class;
 
 static struct dvb_device* dvbdev_find_device (int minor)
 {
-	struct list_head *entry;
+	struct dvb_adapter *adap;
 
-	list_for_each (entry, &dvb_adapter_list) {
-		struct list_head *entry0;
-		struct dvb_adapter *adap;
-		adap = list_entry (entry, struct dvb_adapter, list_head);
-		list_for_each (entry0, &adap->device_list) {
-			struct dvb_device *dev;
-			dev = list_entry (entry0, struct dvb_device, list_head);
+	list_for_each_entry(adap, &dvb_adapter_list, list_head) {
+		struct dvb_device *dev;
+		list_for_each_entry(dev, &adap->device_list, list_head)
 			if (nums2minor(adap->num, dev->type, dev->id) == minor)
 				return dev;
-		}
 	}
 
 	return NULL;
@@ -180,13 +174,10 @@ static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
 	u32 id = 0;
 
 	while (id < DVB_MAX_IDS) {
-		struct list_head *entry;
-		list_for_each (entry, &adap->device_list) {
-			struct dvb_device *dev;
-			dev = list_entry (entry, struct dvb_device, list_head);
+		struct dvb_device *dev;
+		list_for_each_entry(dev, &adap->device_list, list_head)
 			if (dev->type == type && dev->id == id)
 				goto skip;
-		}
 		return id;
 skip:
 		id++;
@@ -200,7 +191,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 {
 	struct dvb_device *dvbdev;
 	struct file_operations *dvbdevfops;
-	struct class_device *clsdev;
+	struct device *clsdev;
 	int id;
 
 	mutex_lock(&dvbdev_register_lock);
@@ -242,10 +233,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 
 	mutex_unlock(&dvbdev_register_lock);
 
-	clsdev = class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR,
-				     nums2minor(adap->num, type, id)),
-				     adap->device, "dvb%d.%s%d", adap->num,
-				     dnames[type], id);
+	clsdev = device_create(dvb_class, adap->device,
+			       MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+			       "dvb%d.%s%d", adap->num, dnames[type], id);
 	if (IS_ERR(clsdev)) {
 		printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
 		       __FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev));
@@ -266,8 +256,8 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
 	if (!dvbdev)
 		return;
 
-	class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
-					dvbdev->type, dvbdev->id)));
+	device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
+		       dvbdev->type, dvbdev->id)));
 
 	list_del (&dvbdev->list_head);
 	kfree (dvbdev->fops);
@@ -281,13 +271,10 @@ static int dvbdev_get_free_adapter_num (void)
 	int num = 0;
 
 	while (num < DVB_MAX_ADAPTERS) {
-		struct list_head *entry;
-		list_for_each (entry, &dvb_adapter_list) {
-			struct dvb_adapter *adap;
-			adap = list_entry (entry, struct dvb_adapter, list_head);
+		struct dvb_adapter *adap;
+		list_for_each_entry(adap, &dvb_adapter_list, list_head)
 			if (adap->num == num)
 				goto skip;
-		}
 		return num;
 skip:
 		num++;

+ 2 - 0
drivers/media/dvb/dvb-usb/Kconfig

@@ -74,6 +74,8 @@ config DVB_USB_DIB0700
 	select DVB_DIB7000M
 	select DVB_DIB3000MC
 	select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_DIB0070
 	help
 	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
 	  USB bridge is also present in devices having the DiB7700 DVB-T-USB

+ 3 - 2
drivers/media/dvb/dvb-usb/dib0700.h

@@ -30,17 +30,19 @@ extern int dvb_usb_dib0700_debug;
 	// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
 	// 2 Byte: MPEG2 mode:  4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
 	// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines)    4LSB(     "                "           )
+#define REQUEST_SET_RC       0x11
 #define REQUEST_GET_VERSION  0x15
 
 struct dib0700_state {
 	u8 channel_state;
 	u16 mt2060_if1[2];
-
+	u8 rc_toggle;
 	u8 is_dib7000pc;
 };
 
 extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
 extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
+extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
 extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
 extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
 extern struct i2c_algorithm dib0700_i2c_algo;
@@ -50,5 +52,4 @@ extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device
 extern int dib0700_device_count;
 extern struct dvb_usb_device_properties dib0700_devices[];
 extern struct usb_device_id dib0700_usb_id_table[];
-
 #endif

+ 21 - 2
drivers/media/dvb/dvb-usb/dib0700_core.c

@@ -13,6 +13,10 @@ int dvb_usb_dib0700_debug;
 module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
 
+static int dvb_usb_dib0700_ir_proto = 1;
+module_param(dvb_usb_dib0700_ir_proto, int, 0644);
+MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
+
 /* expecting rx buffer: request data[0] data[1] ... data[2] */
 static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
 {
@@ -32,7 +36,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
 }
 
 /* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
-static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
+int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
 {
 	u16 index, value;
 	int status;
@@ -260,14 +264,29 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 	return dib0700_ctrl_wr(adap->dev, b, 4);
 }
 
+static int dib0700_rc_setup(struct dvb_usb_device *d)
+{
+	u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
+	int i = dib0700_ctrl_wr(d, rc_setup, 3);
+	if (i<0) {
+		err("ir protocol setup failed");
+		return -1;
+	}
+	return 0;
+}
+
 static int dib0700_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	int i;
+	struct dvb_usb_device *dev;
 
 	for (i = 0; i < dib0700_device_count; i++)
-		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0)
+		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0)
+		{
+			dib0700_rc_setup(dev);
 			return 0;
+		}
 
 	return -ENODEV;
 }

+ 665 - 11
drivers/media/dvb/dvb-usb/dib0700_devices.c

@@ -4,7 +4,7 @@
  *	under the terms of the GNU General Public License as published by the Free
  *	Software Foundation, version 2.
  *
- *  Copyright (C) 2005-6 DiBcom, SA
+ *  Copyright (C) 2005-7 DiBcom, SA
  */
 #include "dib0700.h"
 
@@ -12,13 +12,19 @@
 #include "dib7000m.h"
 #include "dib7000p.h"
 #include "mt2060.h"
+#include "mt2266.h"
+#include "dib0070.h"
 
 static int force_lna_activation;
 module_param(force_lna_activation, int, 0644);
 MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
 		"if applicable for the device (default: 0=automatic/off).");
 
-/* Hauppauge Nova-T 500
+struct dib0700_adapter_state {
+	int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *);
+};
+
+/* Hauppauge Nova-T 500 (aka Bristol)
  *  has a LNA on GPIO0 which is enabled by setting 1 */
 static struct mt2060_config bristol_mt2060_config[2] = {
 	{
@@ -96,6 +102,321 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
 		st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
 }
 
+/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
+
+/* MT226x */
+static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
+	{
+		BAND_UHF, // band_caps
+
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+		1130,  // inv_gain
+		21,  // time_stabiliz
+
+		0,  // alpha_level
+		118,  // thlock
+
+		0,     // wbd_inv
+		3530,  // wbd_ref
+		1,     // wbd_sel
+		0,     // wbd_alpha
+
+		65535,  // agc1_max
+		33770,  // agc1_min
+		65535,  // agc2_max
+		23592,  // agc2_min
+
+		0,    // agc1_pt1
+		62,   // agc1_pt2
+		255,  // agc1_pt3
+		64,   // agc1_slope1
+		64,   // agc1_slope2
+		132,  // agc2_pt1
+		192,  // agc2_pt2
+		80,   // agc2_slope1
+		80,   // agc2_slope2
+
+		17,  // alpha_mant
+		27,  // alpha_exp
+		23,  // beta_mant
+		51,  // beta_exp
+
+		1,  // perform_agc_softsplit
+	}, {
+		BAND_VHF | BAND_LBAND, // band_caps
+
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+
+		2372, // inv_gain
+		21,   // time_stabiliz
+
+		0,    // alpha_level
+		118,  // thlock
+
+		0,    // wbd_inv
+		3530, // wbd_ref
+		1,     // wbd_sel
+		0,    // wbd_alpha
+
+		65535, // agc1_max
+		0,     // agc1_min
+		65535, // agc2_max
+		23592, // agc2_min
+
+		0,    // agc1_pt1
+		128,  // agc1_pt2
+		128,  // agc1_pt3
+		128,  // agc1_slope1
+		0,    // agc1_slope2
+		128,  // agc2_pt1
+		253,  // agc2_pt2
+		81,   // agc2_slope1
+		0,    // agc2_slope2
+
+		17,  // alpha_mant
+		27,  // alpha_exp
+		23,  // beta_mant
+		51,  // beta_exp
+
+		1,  // perform_agc_softsplit
+	}
+};
+
+static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
+	60000, 30000, // internal, sampling
+	1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+	0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+	0, // ifreq
+	20452225, // timf
+};
+
+static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
+	{	.output_mpeg2_in_188_bytes = 1,
+		.hostbus_diversity = 1,
+		.tuner_is_baseband = 1,
+
+		.agc_config_count = 2,
+		.agc = stk7700d_7000p_mt2266_agc_config,
+		.bw  = &stk7700d_mt2266_pll_config,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+	},
+	{	.output_mpeg2_in_188_bytes = 1,
+		.hostbus_diversity = 1,
+		.tuner_is_baseband = 1,
+
+		.agc_config_count = 2,
+		.agc = stk7700d_7000p_mt2266_agc_config,
+		.bw  = &stk7700d_mt2266_pll_config,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+	}
+};
+
+static struct mt2266_config stk7700d_mt2266_config[2] = {
+	{	.i2c_address = 0x60
+	},
+	{	.i2c_address = 0x60
+	}
+};
+
+static int stk7700d_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);
+		dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+		dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,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_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct i2c_adapter *tun_i2c;
+	tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+	return dvb_attach(mt2266_attach, adap->fe, tun_i2c,
+		&stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;;
+}
+
+#define DEFAULT_RC_INTERVAL 150
+
+static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
+
+static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 key[4];
+	int i;
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct dib0700_state *st = d->priv;
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+	i=dib0700_ctrl_rd(d,rc_request,2,key,4);
+	if (i<=0) {
+		err("RC Query Failed");
+		return -1;
+	}
+	if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
+	if (key[3-1]!=st->rc_toggle) {
+		for (i=0;i<d->props.rc_key_map_size; i++) {
+			if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+				*event = keymap[i].event;
+				*state = REMOTE_KEY_PRESSED;
+				st->rc_toggle=key[3-1];
+				return 0;
+			}
+		}
+		err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]);
+	}
+	return 0;
+}
+
+static struct dvb_usb_rc_key dib0700_rc_keys[] = {
+	/* Key codes for the tiny Pinnacle remote*/
+	{ 0x07, 0x00, KEY_MUTE },
+	{ 0x07, 0x01, KEY_MENU }, // Pinnacle logo
+	{ 0x07, 0x39, KEY_POWER },
+	{ 0x07, 0x03, KEY_VOLUMEUP },
+	{ 0x07, 0x09, KEY_VOLUMEDOWN },
+	{ 0x07, 0x06, KEY_CHANNELUP },
+	{ 0x07, 0x0c, KEY_CHANNELDOWN },
+	{ 0x07, 0x0f, KEY_1 },
+	{ 0x07, 0x15, KEY_2 },
+	{ 0x07, 0x10, KEY_3 },
+	{ 0x07, 0x18, KEY_4 },
+	{ 0x07, 0x1b, KEY_5 },
+	{ 0x07, 0x1e, KEY_6 },
+	{ 0x07, 0x11, KEY_7 },
+	{ 0x07, 0x21, KEY_8 },
+	{ 0x07, 0x12, KEY_9 },
+	{ 0x07, 0x27, KEY_0 },
+	{ 0x07, 0x24, KEY_SCREEN }, // 'Square' key
+	{ 0x07, 0x2a, KEY_TEXT },   // 'T' key
+	{ 0x07, 0x2d, KEY_REWIND },
+	{ 0x07, 0x30, KEY_PLAY },
+	{ 0x07, 0x33, KEY_FASTFORWARD },
+	{ 0x07, 0x36, KEY_RECORD },
+	{ 0x07, 0x3c, KEY_STOP },
+	{ 0x07, 0x3f, KEY_CANCEL }, // '?' key
+	/* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
+	{ 0xeb, 0x01, KEY_POWER },
+	{ 0xeb, 0x02, KEY_1 },
+	{ 0xeb, 0x03, KEY_2 },
+	{ 0xeb, 0x04, KEY_3 },
+	{ 0xeb, 0x05, KEY_4 },
+	{ 0xeb, 0x06, KEY_5 },
+	{ 0xeb, 0x07, KEY_6 },
+	{ 0xeb, 0x08, KEY_7 },
+	{ 0xeb, 0x09, KEY_8 },
+	{ 0xeb, 0x0a, KEY_9 },
+	{ 0xeb, 0x0b, KEY_VIDEO },
+	{ 0xeb, 0x0c, KEY_0 },
+	{ 0xeb, 0x0d, KEY_REFRESH },
+	{ 0xeb, 0x0f, KEY_EPG },
+	{ 0xeb, 0x10, KEY_UP },
+	{ 0xeb, 0x11, KEY_LEFT },
+	{ 0xeb, 0x12, KEY_OK },
+	{ 0xeb, 0x13, KEY_RIGHT },
+	{ 0xeb, 0x14, KEY_DOWN },
+	{ 0xeb, 0x16, KEY_INFO },
+	{ 0xeb, 0x17, KEY_RED },
+	{ 0xeb, 0x18, KEY_GREEN },
+	{ 0xeb, 0x19, KEY_YELLOW },
+	{ 0xeb, 0x1a, KEY_BLUE },
+	{ 0xeb, 0x1b, KEY_CHANNELUP },
+	{ 0xeb, 0x1c, KEY_VOLUMEUP },
+	{ 0xeb, 0x1d, KEY_MUTE },
+	{ 0xeb, 0x1e, KEY_VOLUMEDOWN },
+	{ 0xeb, 0x1f, KEY_CHANNELDOWN },
+	{ 0xeb, 0x40, KEY_PAUSE },
+	{ 0xeb, 0x41, KEY_HOME },
+	{ 0xeb, 0x42, KEY_MENU }, /* DVD Menu */
+	{ 0xeb, 0x43, KEY_SUBTITLE },
+	{ 0xeb, 0x44, KEY_TEXT }, /* Teletext */
+	{ 0xeb, 0x45, KEY_DELETE },
+	{ 0xeb, 0x46, KEY_TV },
+	{ 0xeb, 0x47, KEY_DVD },
+	{ 0xeb, 0x48, KEY_STOP },
+	{ 0xeb, 0x49, KEY_VIDEO },
+	{ 0xeb, 0x4a, KEY_AUDIO }, /* Music */
+	{ 0xeb, 0x4b, KEY_SCREEN }, /* Pic */
+	{ 0xeb, 0x4c, KEY_PLAY },
+	{ 0xeb, 0x4d, KEY_BACK },
+	{ 0xeb, 0x4e, KEY_REWIND },
+	{ 0xeb, 0x4f, KEY_FASTFORWARD },
+	{ 0xeb, 0x54, KEY_PREVIOUS },
+	{ 0xeb, 0x58, KEY_RECORD },
+	{ 0xeb, 0x5c, KEY_NEXT },
+
+	/* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
+	{ 0x1e, 0x00, KEY_0 },
+	{ 0x1e, 0x01, KEY_1 },
+	{ 0x1e, 0x02, KEY_2 },
+	{ 0x1e, 0x03, KEY_3 },
+	{ 0x1e, 0x04, KEY_4 },
+	{ 0x1e, 0x05, KEY_5 },
+	{ 0x1e, 0x06, KEY_6 },
+	{ 0x1e, 0x07, KEY_7 },
+	{ 0x1e, 0x08, KEY_8 },
+	{ 0x1e, 0x09, KEY_9 },
+	{ 0x1e, 0x0a, KEY_KPASTERISK },
+	{ 0x1e, 0x0b, KEY_RED },
+	{ 0x1e, 0x0c, KEY_RADIO },
+	{ 0x1e, 0x0d, KEY_MENU },
+	{ 0x1e, 0x0e, KEY_GRAVE }, /* # */
+	{ 0x1e, 0x0f, KEY_MUTE },
+	{ 0x1e, 0x10, KEY_VOLUMEUP },
+	{ 0x1e, 0x11, KEY_VOLUMEDOWN },
+	{ 0x1e, 0x12, KEY_CHANNEL },
+	{ 0x1e, 0x14, KEY_UP },
+	{ 0x1e, 0x15, KEY_DOWN },
+	{ 0x1e, 0x16, KEY_LEFT },
+	{ 0x1e, 0x17, KEY_RIGHT },
+	{ 0x1e, 0x18, KEY_VIDEO },
+	{ 0x1e, 0x19, KEY_AUDIO },
+	{ 0x1e, 0x1a, KEY_MEDIA },
+	{ 0x1e, 0x1b, KEY_EPG },
+	{ 0x1e, 0x1c, KEY_TV },
+	{ 0x1e, 0x1e, KEY_NEXT },
+	{ 0x1e, 0x1f, KEY_BACK },
+	{ 0x1e, 0x20, KEY_CHANNELUP },
+	{ 0x1e, 0x21, KEY_CHANNELDOWN },
+	{ 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
+	{ 0x1e, 0x25, KEY_OK },
+	{ 0x1e, 0x29, KEY_BLUE},
+	{ 0x1e, 0x2e, KEY_GREEN },
+	{ 0x1e, 0x30, KEY_PAUSE },
+	{ 0x1e, 0x32, KEY_REWIND },
+	{ 0x1e, 0x34, KEY_FASTFORWARD },
+	{ 0x1e, 0x35, KEY_PLAY },
+	{ 0x1e, 0x36, KEY_STOP },
+	{ 0x1e, 0x37, KEY_RECORD },
+	{ 0x1e, 0x38, KEY_YELLOW },
+	{ 0x1e, 0x3b, KEY_GOTO },
+	{ 0x1e, 0x3d, KEY_POWER },
+};
+
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
 static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
 	BAND_UHF | BAND_VHF,       // band_caps
@@ -194,6 +515,7 @@ static struct dibx000_bandwidth_config stk7700p_pll_config = {
 	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
 	60258167, // ifreq
 	20452225, // timf
+	30000000, // xtal
 };
 
 static struct dib7000m_config stk7700p_dib7000m_config = {
@@ -213,6 +535,7 @@ static struct dib7000m_config stk7700p_dib7000m_config = {
 static struct dib7000p_config stk7700p_dib7000p_config = {
 	.output_mpeg2_in_188_bytes = 1,
 
+	.agc_config_count = 1,
 	.agc = &stk7700p_7000p_mt2060_agc_config,
 	.bw  = &stk7700p_pll_config,
 
@@ -267,27 +590,245 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
 		st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
 }
 
+/* DIB7070 generic */
+static struct dibx000_agc_config dib7070_agc_config = {
+	BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+	600, // inv_gain
+	10,  // time_stabiliz
+
+	0,  // alpha_level
+	118,  // thlock
+
+	0,     // wbd_inv
+	3530,  // wbd_ref
+	1,     // wbd_sel
+	5,     // wbd_alpha
+
+	65535,  // agc1_max
+		0,  // agc1_min
+
+	65535,  // agc2_max
+	0,      // agc2_min
+
+	0,      // agc1_pt1
+	40,     // agc1_pt2
+	183,    // agc1_pt3
+	206,    // agc1_slope1
+	255,    // agc1_slope2
+	72,     // agc2_pt1
+	152,    // agc2_pt2
+	88,     // agc2_slope1
+	90,     // agc2_slope2
+
+	17,  // alpha_mant
+	27,  // alpha_exp
+	23,  // beta_mant
+	51,  // beta_exp
+
+	0,  // perform_agc_softsplit
+};
+
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+	return dib7000p_set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	return dib7000p_set_gpio(fe, 9, 0, onoff);
+}
+
+static struct dib0070_config dib7070p_dib0070_config[2] = {
+	{
+		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+		.reset = dib7070_tuner_reset,
+		.sleep = dib7070_tuner_sleep,
+		.clock_khz = 12000,
+		.clock_pad_drive = 4
+	}, {
+		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+		.reset = dib7070_tuner_reset,
+		.sleep = dib7070_tuner_sleep,
+		.clock_khz = 12000,
+
+	}
+};
+
+static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+
+	u16 offset;
+	u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+	switch (band) {
+		case BAND_VHF: offset = 950; break;
+		case BAND_UHF:
+		default: offset = 550; break;
+	}
+	deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
+	dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+	return state->set_param_save(fe, fep);
+}
+
+static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	if (adap->id == 0) {
+		if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
+			return -ENODEV;
+	} else {
+		if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
+			return -ENODEV;
+	}
+
+	st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+	adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+	return 0;
+}
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+	60000, 15000, // internal, sampling
+	1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+	0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+	(0 << 25) | 0, // ifreq = 0.000000 MHz
+	20452225, // timf
+	12000000, // xtal_hz
+};
+
+static struct dib7000p_config dib7070p_dib7000p_config = {
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 1,
+	.agc = &dib7070_agc_config,
+	.bw  = &dib7070_bw_config_12_mhz,
+
+	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.hostbus_diversity = 1,
+};
+
+/* STK7070P */
+static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	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);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config);
+
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config);
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* STK7070PD */
+static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
+	{
+		.output_mpeg2_in_188_bytes = 1,
+
+		.agc_config_count = 1,
+		.agc = &dib7070_agc_config,
+		.bw  = &dib7070_bw_config_12_mhz,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+		.hostbus_diversity = 1,
+	}, {
+		.output_mpeg2_in_188_bytes = 1,
+
+		.agc_config_count = 1,
+		.agc = &dib7070_agc_config,
+		.bw  = &dib7070_bw_config_12_mhz,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+		.hostbus_diversity = 1,
+	}
+};
+
+static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+{
+	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);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config);
+
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
+{
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* DVB-USB and USB stuff follows */
 struct usb_device_id dib0700_usb_id_table[] = {
-		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
+/* 0 */	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
 		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P_PC) },
 
 		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
 		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
 		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
-		{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
+/* 5 */	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
 		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500) },
 		{ USB_DEVICE(USB_VID_UNIWILL,   USB_PID_UNIWILL_STK7700P) },
 		{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
 		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
-		{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
-		{ }		/* Terminating entry */
+/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
+		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV2000E) },
+		{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
+		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
+		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700D) },
+/* 15 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070P) },
+		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
+		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070PD) },
+		{ 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) },
+		{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
 
 #define DIB0700_DEFAULT_DEVICE_PROPERTIES \
 	.caps              = DVB_USB_IS_AN_I2C_ADAPTER, \
 	.usb_ctrl          = DEVICE_SPECIFIC, \
-	.firmware          = "dvb-usb-dib0700-01.fw", \
+	.firmware          = "dvb-usb-dib0700-03-pre1.fw", \
 	.download_firmware = dib0700_download_firmware, \
 	.no_reconnect      = 1, \
 	.size_of_priv      = sizeof(struct dib0700_state), \
@@ -321,7 +862,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			},
 		},
 
-		.num_device_descs = 6,
+		.num_device_descs = 7,
 		.devices = {
 			{   "DiBcom STK7700P reference design",
 				{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
@@ -336,7 +877,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ NULL },
 			},
 			{   "Compro Videomate U500",
-				{ &dib0700_usb_id_table[6], NULL },
+				{ &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] },
 				{ NULL },
 			},
 			{   "Uniwill STK7700P based (Hama and others)",
@@ -346,8 +887,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{   "Leadtek Winfast DTV Dongle (STK7700P based)",
 				{ &dib0700_usb_id_table[8], NULL },
 				{ NULL },
+			},
+			{   "AVerMedia AVerTV DVB-T Express",
+				{ &dib0700_usb_id_table[20] },
+				{ 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,
@@ -371,8 +921,112 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], 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,
+		.adapter = {
+			{
+				.frontend_attach  = stk7700d_frontend_attach,
+				.tuner_attach     = stk7700d_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}, {
+				.frontend_attach  = stk7700d_frontend_attach,
+				.tuner_attach     = stk7700d_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+			}
+		},
+
+		.num_device_descs = 4,
+		.devices = {
+			{   "Pinnacle PCTV 2000e",
+				{ &dib0700_usb_id_table[11], NULL },
+				{ NULL },
+			},
+			{   "Terratec Cinergy DT XS Diversity",
+				{ &dib0700_usb_id_table[12], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity",
+				{ &dib0700_usb_id_table[13], NULL },
+				{ NULL },
+			},
+			{   "DiBcom STK7700D reference design",
+				{ &dib0700_usb_id_table[14], 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 = 1,
+		.adapter = {
+			{
+				.frontend_attach  = stk7070p_frontend_attach,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 2,
+		.devices = {
+			{   "DiBcom STK7070P reference design",
+				{ &dib0700_usb_id_table[15], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV DVB-T Flash Stick",
+				{ &dib0700_usb_id_table[16], NULL },
+				{ NULL },
+			},
 		}
-	}
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+				.frontend_attach  = stk7070pd_frontend_attach0,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}, {
+				.frontend_attach  = stk7070pd_frontend_attach1,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}
+		},
+
+		.num_device_descs = 2,
+		.devices = {
+			{   "DiBcom STK7070PD reference design",
+				{ &dib0700_usb_id_table[17], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
+				{ &dib0700_usb_id_table[18], NULL },
+				{ NULL },
+			},
+		}
+	},
 };
 
 int dib0700_device_count = ARRAY_SIZE(dib0700_devices);

+ 25 - 3
drivers/media/dvb/dvb-usb/dtt200u.c

@@ -1,5 +1,5 @@
 /* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
- * Typhoon/ Yuan DVB-T USB2.0 receiver.
+ * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
@@ -96,6 +96,7 @@ static struct dvb_usb_device_properties dtt200u_properties;
 static struct dvb_usb_device_properties wt220u_fc_properties;
 static struct dvb_usb_device_properties wt220u_properties;
 static struct dvb_usb_device_properties wt220u_zl0353_properties;
+static struct dvb_usb_device_properties wt220u_miglia_properties;
 
 static int dtt200u_usb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
@@ -103,7 +104,8 @@ static int dtt200u_usb_probe(struct usb_interface *intf,
 	if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0)
+		dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&wt220u_miglia_properties,THIS_MODULE,NULL) == 0)
 		return 0;
 
 	return -ENODEV;
@@ -119,6 +121,7 @@ static struct usb_device_id dtt200u_usb_table [] = {
 	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD)  },
 	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM)  },
 	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD)  },
+	{ USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD)  },
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
@@ -303,6 +306,25 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
 	}
 };
 
+static struct dvb_usb_device_properties wt220u_miglia_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-wt220u-miglia-01.fw",
+
+	.num_adapters = 1,
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "WideView WT-220U PenType Receiver (Miglia)",
+		  .cold_ids = { &dtt200u_usb_table[9], NULL },
+		  /* This device turns into WT220U_ZL0353_WARM when fw
+		     has been uploaded */
+		  .warm_ids = { NULL },
+		},
+		{ NULL },
+	}
+};
+
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver dtt200u_usb_driver = {
 	.name		= "dvb_usb_dtt200u",
@@ -333,6 +355,6 @@ module_init(dtt200u_usb_module_init);
 module_exit(dtt200u_usb_module_exit);
 
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
 MODULE_VERSION("1.0");
 MODULE_LICENSE("GPL");

+ 20 - 6
drivers/media/dvb/dvb-usb/dvb-usb-ids.h

@@ -12,7 +12,7 @@
 /* Vendor IDs */
 #define USB_VID_ADSTECH				0x06e1
 #define USB_VID_AFATECH				0x15a4
-#define USB_VID_ALCOR_MICRO		0x058f
+#define USB_VID_ALCOR_MICRO			0x058f
 #define USB_VID_ALINK				0x05e3
 #define USB_VID_ANCHOR				0x0547
 #define USB_VID_ANUBIS_ELECTRONIC		0x10fd
@@ -34,6 +34,7 @@
 #define USB_VID_LEADTEK				0x0413
 #define USB_VID_LITEON				0x04ca
 #define USB_VID_MEDION				0x1660
+#define USB_VID_MIGLIA				0x18f3
 #define USB_VID_MSI				0x0db0
 #define USB_VID_OPERA1				0x695c
 #define USB_VID_PINNACLE			0x2304
@@ -58,6 +59,7 @@
 #define USB_PID_COMPRO_DVBU2000_UNK_COLD		0x010c
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
 #define USB_PID_COMPRO_VIDEOMATE_U500			0x1e78
+#define USB_PID_COMPRO_VIDEOMATE_U500_PC		0x1e80
 #define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
@@ -66,6 +68,9 @@
 #define USB_PID_DIBCOM_MOD3001_WARM			0x0bc7
 #define USB_PID_DIBCOM_STK7700P				0x1e14
 #define USB_PID_DIBCOM_STK7700P_PC			0x1e78
+#define USB_PID_DIBCOM_STK7700D				0x1ef0
+#define USB_PID_DIBCOM_STK7070P				0x1ebc
+#define USB_PID_DIBCOM_STK7070PD			0x1ebe
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
 #define USB_PID_DPOSH_M9206_COLD			0x9206
 #define USB_PID_DPOSH_M9206_WARM			0xa090
@@ -115,8 +120,17 @@
 #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_TD_STICK			0x9580
+#define USB_PID_AVERMEDIA_EXPRESS			0xb568
 #define USB_PID_AVERMEDIA_VOLAR				0xa807
 #define USB_PID_AVERMEDIA_VOLAR_2			0xb808
+#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
+#define USB_PID_PINNACLE_PCTV2000E			0x022c
+#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH		0x0228
+#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T	0x0229
+#define USB_PID_PCTV_200E				0x020e
+#define USB_PID_PCTV_400E				0x020f
+#define USB_PID_PCTV_450E				0x0222
 #define USB_PID_NEBULA_DIGITV				0x0201
 #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
@@ -136,9 +150,6 @@
 #define USB_PID_MSI_MEGASKY580_55801			0x5581
 #define USB_PID_KYE_DVB_T_COLD				0x701e
 #define USB_PID_KYE_DVB_T_WARM				0x701f
-#define USB_PID_PCTV_200E				0x020e
-#define USB_PID_PCTV_400E				0x020f
-#define USB_PID_PCTV_450E				0x0222
 #define USB_PID_LITEON_DVB_T_COLD			0xf000
 #define USB_PID_LITEON_DVB_T_WARM			0xf001
 #define USB_PID_DIGIVOX_MINI_SL_COLD			0xe360
@@ -148,8 +159,11 @@
 #define USB_PID_WINFAST_DTV_DONGLE_COLD			0x6025
 #define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P		0x6f00
-#define USB_PID_GENPIX_8PSK_COLD			0x0200
-#define USB_PID_GENPIX_8PSK_WARM			0x0201
+#define USB_PID_GENPIX_8PSK_REV_1_COLD			0x0200
+#define USB_PID_GENPIX_8PSK_REV_1_WARM			0x0201
+#define USB_PID_GENPIX_8PSK_REV_2			0x0202
+#define USB_PID_GENPIX_SKYWALKER_1			0x0203
+#define USB_PID_GENPIX_SKYWALKER_CW3K			0x0204
 #define USB_PID_SIGMATEK_DVB_110			0x6610
 #define USB_PID_MSI_DIGI_VOX_MINI_II			0x1513
 #define USB_PID_OPERA1_COLD				0x2830

+ 1 - 1
drivers/media/dvb/dvb-usb/dvb-usb-init.c

@@ -24,7 +24,7 @@ MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0
 
 static int dvb_usb_force_pid_filter_usage;
 module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
-MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
+MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
 
 static int dvb_usb_adapter_init(struct dvb_usb_device *d)
 {

+ 51 - 33
drivers/media/dvb/dvb-usb/gp8psk-fe.c

@@ -1,7 +1,8 @@
 /* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
  *
- * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
  *
  * Thanks to GENPIX for the sample code used to implement this module.
  *
@@ -17,27 +18,39 @@
 
 struct gp8psk_fe_state {
 	struct dvb_frontend fe;
-
 	struct dvb_usb_device *d;
-
+	u8 lock;
 	u16 snr;
-
-	unsigned long next_snr_check;
+	unsigned long next_status_check;
+	unsigned long status_check_interval;
 };
 
+static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
+{
+	u8 buf[6];
+	if (time_after(jiffies,st->next_status_check)) {
+		gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1);
+		gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6);
+		st->snr = (buf[1]) << 8 | buf[0];
+		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
+	}
+	return 0;
+}
+
 static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
 {
 	struct gp8psk_fe_state *st = fe->demodulator_priv;
-	u8 lock;
+	gp8psk_fe_update_status(st);
 
-	if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
-		return -EINVAL;
-
-	if (lock)
+	if (st->lock)
 		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
 	else
 		*status = 0;
 
+	if (*status & FE_HAS_LOCK)
+		st->status_check_interval = 1000;
+	else
+		st->status_check_interval = 100;
 	return 0;
 }
 
@@ -60,33 +73,29 @@ static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
 static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
 	struct gp8psk_fe_state *st = fe->demodulator_priv;
-	u8 buf[2];
-
-	if (time_after(jiffies,st->next_snr_check)) {
-		gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
-		*snr = (int)(buf[1]) << 8 | buf[0];
-		/* snr is reported in dBu*256 */
-		/* snr / 38.4 ~= 100% strength */
-		/* snr * 17 returns 100% strength as 65535 */
-		if (*snr <= 3855)
-			*snr = (*snr<<4) + *snr; // snr * 17
-		else
-			*snr = 65535;
-		st->next_snr_check = jiffies + (10*HZ)/1000;
-	} else {
-		*snr = st->snr;
-	}
+	gp8psk_fe_update_status(st);
+	/* snr is reported in dBu*256 */
+	*snr = st->snr;
 	return 0;
 }
 
 static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
 {
-	return gp8psk_fe_read_snr(fe, strength);
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	gp8psk_fe_update_status(st);
+	/* snr is reported in dBu*256 */
+	/* snr / 38.4 ~= 100% strength */
+	/* snr * 17 returns 100% strength as 65535 */
+	if (st->snr > 0xf00)
+		*strength = 0xffff;
+	else
+		*strength = (st->snr << 4) + st->snr; /* snr*17 */
+	return 0;
 }
 
 static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 {
-	tune->min_delay_ms = 800;
+	tune->min_delay_ms = 200;
 	return 0;
 }
 
@@ -124,7 +133,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
 
 	gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
 
-	state->next_snr_check = jiffies;
+	state->lock = 0;
+	state->next_status_check = jiffies;
+	state->status_check_interval = 200;
 
 	return 0;
 }
@@ -190,6 +201,12 @@ static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t volt
 	return 0;
 }
 
+static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+	return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0);
+}
+
 static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
 {
 	struct gp8psk_fe_state* state = fe->demodulator_priv;
@@ -235,10 +252,10 @@ success:
 
 static struct dvb_frontend_ops gp8psk_fe_ops = {
 	.info = {
-		.name			= "Genpix 8psk-USB DVB-S",
+		.name			= "Genpix 8psk-to-USB2 DVB-S",
 		.type			= FE_QPSK,
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
+		.frequency_min		= 800000,
+		.frequency_max		= 2250000,
 		.frequency_stepsize	= 100,
 		.symbol_rate_min        = 1000000,
 		.symbol_rate_max        = 45000000,
@@ -269,4 +286,5 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
 	.set_tone = gp8psk_fe_set_tone,
 	.set_voltage = gp8psk_fe_set_voltage,
 	.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+	.enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage
 };

+ 71 - 22
drivers/media/dvb/dvb-usb/gp8psk.c

@@ -1,7 +1,8 @@
 /* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
  *
- * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
  *
  * Thanks to GENPIX for the sample code used to implement this module.
  *
@@ -40,7 +41,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
 	}
 
 	if (ret < 0 || ret != blen) {
-		warn("usb in operation failed.");
+		warn("usb in %d operation failed.", req);
 		ret = -EIO;
 	} else
 		ret = 0;
@@ -97,10 +98,10 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
 	if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
 		goto out_rel_fw;
 
-	info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
+	info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware);
 
 	ptr = fw->data;
-	buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+	buf = kmalloc(64, GFP_KERNEL | GFP_DMA);
 
 	while (ptr[0] != 0xff) {
 		u16 buflen = ptr[0] + 4;
@@ -129,25 +130,34 @@ out_rel_fw:
 static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
 	u8 status, buf;
+	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+
 	if (onoff) {
 		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
-		if (! (status & 0x01))  /* started */
+		if (! (status & bm8pskStarted)) {  /* started */
+			if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+				gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);
 			if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
 				return -EINVAL;
+		}
 
-		if (! (status & 0x02)) /* BCM4500 firmware loaded */
-			if(gp8psk_load_bcm4500fw(d))
-				return EINVAL;
+		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+			if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */
+				if(gp8psk_load_bcm4500fw(d))
+					return EINVAL;
 
-		if (! (status & 0x04)) /* LNB Power */
+		if (! (status & bmIntersilOn)) /* LNB Power */
 			if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
 					&buf, 1))
 				return EINVAL;
 
-		/* Set DVB mode */
-		if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
-			return -EINVAL;
-		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+		/* Set DVB mode to 1 */
+		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+			if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+				return EINVAL;
+		/* Abort possible TS (if previous tune crashed) */
+		if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))
+			return EINVAL;
 	} else {
 		/* Turn off LNB power */
 		if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
@@ -155,11 +165,28 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
 		/* Turn off 8psk power */
 		if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
 			return -EINVAL;
-
+		if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+			gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0);
 	}
 	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)
 {
@@ -177,12 +204,22 @@ static struct dvb_usb_device_properties gp8psk_properties;
 static int gp8psk_usb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+	int ret;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	ret =  dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+	if (ret == 0) {
+		info("found Genpix USB device pID = %x (hex)",
+			le16_to_cpu(udev->descriptor.idProduct));
+	}
+	return ret;
 }
 
 static struct usb_device_id gp8psk_usb_table [] = {
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) },
 	    { 0 },
 };
 MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
@@ -213,12 +250,24 @@ static struct dvb_usb_device_properties gp8psk_properties = {
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
-	.num_device_descs = 1,
+	.num_device_descs = 4,
 	.devices = {
-		{ .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+		{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
 		  .cold_ids = { &gp8psk_usb_table[0], NULL },
 		  .warm_ids = { &gp8psk_usb_table[1], NULL },
 		},
+		{ .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver",
+		  .cold_ids = { NULL },
+		  .warm_ids = { &gp8psk_usb_table[2], NULL },
+		},
+		{ .name = "Genpix SkyWalker-1 DVB-S receiver",
+		  .cold_ids = { NULL },
+		  .warm_ids = { &gp8psk_usb_table[3], NULL },
+		},
+		{ .name = "Genpix SkyWalker-CW3K DVB-S receiver",
+		  .cold_ids = { NULL },
+		  .warm_ids = { &gp8psk_usb_table[4], NULL },
+		},
 		{ NULL },
 	}
 };
@@ -253,6 +302,6 @@ module_init(gp8psk_usb_module_init);
 module_exit(gp8psk_usb_module_exit);
 
 MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
-MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
-MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S");
+MODULE_VERSION("1.1");
 MODULE_LICENSE("GPL");

+ 25 - 7
drivers/media/dvb/dvb-usb/gp8psk.h

@@ -1,7 +1,8 @@
 /* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
  *
  * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
  *
  * Thanks to GENPIX for the sample code used to implement this module.
  *
@@ -30,21 +31,37 @@ extern int dvb_usb_gp8psk_debug;
 #define TH_COMMAND_IN                     0xC0
 #define TH_COMMAND_OUT                    0xC1
 
-/* command bytes */
-#define GET_8PSK_CONFIG                 0x80
+/* gp8psk commands */
+
+#define GET_8PSK_CONFIG                 0x80    /* in */
 #define SET_8PSK_CONFIG                 0x81
+#define I2C_WRITE			0x83
+#define I2C_READ			0x84
 #define ARM_TRANSFER                    0x85
 #define TUNE_8PSK                       0x86
-#define GET_SIGNAL_STRENGTH             0x87
+#define GET_SIGNAL_STRENGTH             0x87    /* in */
 #define LOAD_BCM4500                    0x88
-#define BOOT_8PSK                       0x89
-#define START_INTERSIL                  0x8A
+#define BOOT_8PSK                       0x89    /* in */
+#define START_INTERSIL                  0x8A    /* in */
 #define SET_LNB_VOLTAGE                 0x8B
 #define SET_22KHZ_TONE                  0x8C
 #define SEND_DISEQC_COMMAND             0x8D
 #define SET_DVB_MODE                    0x8E
 #define SET_DN_SWITCH                   0x8F
-#define GET_SIGNAL_LOCK                 0x90
+#define GET_SIGNAL_LOCK                 0x90    /* in */
+#define GET_SERIAL_NUMBER               0x93    /* in */
+#define USE_EXTRA_VOLT                  0x94
+#define CW3K_INIT			0x9d
+
+/* PSK_configuration bits */
+#define bm8pskStarted                   0x01
+#define bm8pskFW_Loaded                 0x02
+#define bmIntersilOn                    0x04
+#define bmDVBmode                       0x08
+#define bm22kHz                         0x10
+#define bmSEL18V                        0x20
+#define bmDCtuned                       0x40
+#define bmArmed                         0x80
 
 /* Satellite modulation modes */
 #define ADV_MOD_DVB_QPSK 0     /* DVB-S QPSK */
@@ -75,5 +92,6 @@ 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

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

@@ -159,7 +159,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 		return 0;
 	}
 
-	for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++)
+	for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++)
 		if (vp7045_rc_keys[i].data == key) {
 			*state = REMOTE_KEY_PRESSED;
 			*event = vp7045_rc_keys[i].event;

+ 32 - 1
drivers/media/dvb/frontends/Kconfig

@@ -283,6 +283,14 @@ config DVB_LGDT330X
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
 	  to support this frontend.
 
+config DVB_S5H1409
+	tristate "Samsung S5H1409 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
 comment "Tuners/PLL support"
 	depends on DVB_CORE
 
@@ -291,7 +299,7 @@ config DVB_PLL
 	depends on DVB_CORE && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
-	  This module driver a number of tuners based on PLL chips with a
+	  This module drives a number of tuners based on PLL chips with a
 	  common I2C interface. Say Y when you want to support these tuners.
 
 config DVB_TDA826X
@@ -322,6 +330,29 @@ config DVB_TUNER_MT2060
 	help
 	  A driver for the silicon IF tuner MT2060 from Microtune.
 
+config DVB_TUNER_MT2266
+	tristate "Microtune MT2266 silicon tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner MT2266 from Microtune.
+
+config DVB_TUNER_MT2131
+	tristate "Microtune MT2131 silicon tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner MT2131 from Microtune.
+
+config DVB_TUNER_DIB0070
+	tristate "DiBcom DiB0070 silicon base-band tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner DiB0070 from DiBcom.
+	  This device is only used inside a SiP called togther with a
+	  demodulator for now.
+
 comment "Miscellaneous devices"
 	depends on DVB_CORE
 

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

@@ -40,5 +40,9 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
 obj-$(CONFIG_DVB_TDA827X) += tda827x.o
 obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
+obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
 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

+ 0 - 1
drivers/media/dvb/frontends/bcm3510.c

@@ -33,7 +33,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/jiffies.h>

+ 0 - 1
drivers/media/dvb/frontends/cx22700.c

@@ -23,7 +23,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include "dvb_frontend.h"

+ 0 - 1
drivers/media/dvb/frontends/cx24110.c

@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include "dvb_frontend.h"

+ 0 - 1
drivers/media/dvb/frontends/cx24123.c

@@ -23,7 +23,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include "dvb_frontend.h"

+ 580 - 0
drivers/media/dvb/frontends/dib0070.c

@@ -0,0 +1,580 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib0070.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0)
+
+#define DIB0070_P1D  0x00
+#define DIB0070_P1F  0x01
+#define DIB0070_P1G  0x03
+#define DIB0070S_P1A 0x02
+
+struct dib0070_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe;
+	const struct dib0070_config *cfg;
+	u16 wbd_ff_offset;
+	u8 revision;
+};
+
+static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
+{
+	u8 b[2];
+	struct i2c_msg msg[2] = {
+		{ .addr = state->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b,  .len = 2 },
+	};
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "DiB0070 I2C read failed\n");
+		return 0;
+	}
+	return (b[0] << 8) | b[1];
+}
+
+static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+{
+	u8 b[3] = { reg, val >> 8, val & 0xff };
+	struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "DiB0070 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0)
+
+static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	u16 tmp = 0;
+	tmp = dib0070_read_reg(st, 0x02) & 0x3fff;
+
+    switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) {
+		case  8000:
+			tmp |= (0 << 14);
+			break;
+		case  7000:
+			tmp |= (1 << 14);
+			break;
+	case  6000:
+			tmp |= (2 << 14);
+			break;
+	case 5000:
+		default:
+			tmp |= (3 << 14);
+			break;
+	}
+	dib0070_write_reg(st, 0x02, tmp);
+	return 0;
+}
+
+static void dib0070_captrim(struct dib0070_state *st, u16 LO4)
+{
+	int8_t captrim, fcaptrim, step_sign, step;
+	u16 adc, adc_diff = 3000;
+
+
+
+	dib0070_write_reg(st, 0x0f, 0xed10);
+	dib0070_write_reg(st, 0x17,    0x0034);
+
+	dib0070_write_reg(st, 0x18, 0x0032);
+	msleep(2);
+
+	step = captrim = fcaptrim = 64;
+
+	do {
+		step /= 2;
+		dib0070_write_reg(st, 0x14, LO4 | captrim);
+		msleep(1);
+		adc = dib0070_read_reg(st, 0x19);
+
+		dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024);
+
+		if (adc >= 400) {
+			adc -= 400;
+			step_sign = -1;
+		} else {
+			adc = 400 - adc;
+			step_sign = 1;
+		}
+
+		if (adc < adc_diff) {
+			dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff);
+			adc_diff = adc;
+			fcaptrim = captrim;
+
+
+
+		}
+		captrim += (step_sign * step);
+	} while (step >= 1);
+
+	dib0070_write_reg(st, 0x14, LO4 | fcaptrim);
+	dib0070_write_reg(st, 0x18, 0x07ff);
+}
+
+#define LPF	100                       // define for the loop filter 100kHz by default 16-07-06
+#define LO4_SET_VCO_HFDIV(l, v, h)   l |= ((v) << 11) | ((h) << 7)
+#define LO4_SET_SD(l, s)             l |= ((s) << 14) | ((s) << 12)
+#define LO4_SET_CTRIM(l, c)          l |=  (c) << 10
+static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf);
+
+	u8 band = BAND_OF_FREQUENCY(freq), c;
+
+	/*******************VCO***********************************/
+	u16 lo4 = 0;
+
+	u8 REFDIV, PRESC = 2;
+	u32 FBDiv, Rest, FREF, VCOF_kHz;
+	u16 Num, Den;
+	/*******************FrontEnd******************************/
+	u16 value = 0;
+
+	dprintk( "Tuning for Band: %hd (%d kHz)", band, freq);
+
+
+	dib0070_write_reg(st, 0x17, 0x30);
+
+	dib0070_set_bandwidth(fe, ch);	/* c is used as HF */
+	switch (st->revision) {
+		case DIB0070S_P1A:
+			switch (band) {
+				case BAND_LBAND:
+					LO4_SET_VCO_HFDIV(lo4, 1, 1);
+					c = 2;
+					break;
+				case BAND_SBAND:
+					LO4_SET_VCO_HFDIV(lo4, 0, 0);
+					LO4_SET_CTRIM(lo4, 1);;
+					c = 1;
+					break;
+				case BAND_UHF:
+				default:
+					if (freq < 570000) {
+						LO4_SET_VCO_HFDIV(lo4, 1, 3);
+						PRESC = 6; c = 6;
+					} else if (freq < 680000) {
+						LO4_SET_VCO_HFDIV(lo4, 0, 2);
+						c = 4;
+					} else {
+						LO4_SET_VCO_HFDIV(lo4, 1, 2);
+						c = 4;
+					}
+					break;
+			} break;
+
+		case DIB0070_P1G:
+		case DIB0070_P1F:
+		default:
+			switch (band) {
+				case BAND_FM:
+						LO4_SET_VCO_HFDIV(lo4, 0, 7);
+						c = 24;
+					break;
+				case BAND_LBAND:
+						LO4_SET_VCO_HFDIV(lo4, 1, 0);
+						c = 2;
+					break;
+				case BAND_VHF:
+					if (freq < 180000) {
+						LO4_SET_VCO_HFDIV(lo4, 0, 3);
+						c = 16;
+					} else if (freq < 190000) {
+						LO4_SET_VCO_HFDIV(lo4, 1, 3);
+						c = 16;
+					} else {
+						LO4_SET_VCO_HFDIV(lo4, 0, 6);
+						c = 12;
+					}
+					break;
+
+				case BAND_UHF:
+				default:
+					if (freq < 570000) {
+						LO4_SET_VCO_HFDIV(lo4, 1, 5);
+						c = 6;
+					} else if (freq < 700000) {
+						LO4_SET_VCO_HFDIV(lo4, 0, 1);
+						c = 4;
+					} else {
+						LO4_SET_VCO_HFDIV(lo4, 1, 1);
+						c = 4;
+					}
+					break;
+			}
+		break;
+	}
+
+	dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf);
+	dprintk( "VCO = %hd", (lo4 >> 11) & 0x3);
+
+
+	VCOF_kHz = (c * freq) * 2;
+	dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq);
+
+	switch (band) {
+		case BAND_VHF:
+			REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000);
+			break;
+		case BAND_FM:
+			REFDIV = (u8) ((st->cfg->clock_khz) / 1000);
+			break;
+		default:
+			REFDIV = (u8) ( st->cfg->clock_khz  / 10000);
+			break;
+	}
+	FREF = st->cfg->clock_khz / REFDIV;
+
+	dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF);
+
+
+
+	switch (st->revision) {
+		case DIB0070S_P1A:
+			FBDiv = (VCOF_kHz / PRESC / FREF);
+			Rest  = (VCOF_kHz / PRESC) - FBDiv * FREF;
+			break;
+
+		case DIB0070_P1G:
+		case DIB0070_P1F:
+		default:
+			FBDiv = (freq / (FREF / 2));
+			Rest  = 2 * freq - FBDiv * FREF;
+			break;
+	}
+
+
+	     if (Rest < LPF)              Rest = 0;
+	else if (Rest < 2 * LPF)          Rest = 2 * LPF;
+	else if (Rest > (FREF - LPF))   { Rest = 0 ; FBDiv += 1; }
+	else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF;
+	Rest = (Rest * 6528) / (FREF / 10);
+	dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest);
+
+	Num = 0;
+	Den = 1;
+
+	if (Rest > 0) {
+		LO4_SET_SD(lo4, 1);
+		Den = 255;
+		Num = (u16)Rest;
+	}
+	dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1);
+
+
+
+	dib0070_write_reg(st, 0x11, (u16)FBDiv);
+
+
+	dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV);
+
+
+	dib0070_write_reg(st, 0x13, Num);
+
+
+	value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001;
+
+	switch (band) {
+		case BAND_UHF:   value |= 0x4000 | 0x0800; break;
+		case BAND_LBAND: value |= 0x2000 | 0x0400; break;
+		default:         value |= 0x8000 | 0x1000; break;
+	}
+	dib0070_write_reg(st, 0x20, value);
+
+	dib0070_captrim(st, lo4);
+	if (st->revision == DIB0070S_P1A) {
+		if (band == BAND_SBAND)
+			dib0070_write_reg(st, 0x15, 0x16e2);
+		else
+			dib0070_write_reg(st, 0x15, 0x56e5);
+	}
+
+
+
+	switch (band) {
+		case BAND_UHF:   value = 0x7c82; break;
+		case BAND_LBAND: value = 0x7c84; break;
+		default:         value = 0x7c81; break;
+	}
+	dib0070_write_reg(st, 0x0f, value);
+	dib0070_write_reg(st, 0x06, 0x3fff);
+
+	/* Front End */
+	/* c == TUNE, value = SWITCH */
+	c = 0;
+	value = 0;
+	switch (band) {
+		case BAND_FM:
+			c = 0; value = 1;
+		break;
+
+		case BAND_VHF:
+			if (freq <= 180000) c = 0;
+			else if (freq <= 188200) c = 1;
+			else if (freq <= 196400) c = 2;
+			else c = 3;
+			value = 1;
+		break;
+
+		case BAND_LBAND:
+			if (freq <= 1500000) c = 0;
+			else if (freq <= 1600000) c = 1;
+			else c = 3;
+		break;
+
+		case BAND_SBAND:
+			c = 7;
+			dib0070_write_reg(st, 0x1d,0xFFFF);
+		break;
+
+		case BAND_UHF:
+		default:
+			if (st->cfg->flip_chip) {
+				if (freq <= 550000) c = 0;
+				else if (freq <= 590000) c = 1;
+				else if (freq <= 666000) c = 3;
+				else c = 5;
+			} else {
+				if (freq <= 550000) c = 2;
+				else if (freq <= 650000) c = 3;
+				else if (freq <= 750000) c = 5;
+				else if (freq <= 850000) c = 6;
+				else c = 7;
+			}
+			value = 2;
+		break;
+	}
+
+	/* default: LNA_MATCH=7, BIAS=3 */
+	dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0));
+	dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127));
+	dib0070_write_reg(st, 0x0d, 0x0d80);
+
+
+	dib0070_write_reg(st, 0x18,   0x07ff);
+	dib0070_write_reg(st, 0x17, 0x0033);
+
+	return 0;
+}
+
+static int dib0070_wakeup(struct dvb_frontend *fe)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	if (st->cfg->sleep)
+		st->cfg->sleep(fe, 0);
+	return 0;
+}
+
+static int dib0070_sleep(struct dvb_frontend *fe)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	if (st->cfg->sleep)
+		st->cfg->sleep(fe, 1);
+	return 0;
+}
+
+static u16 dib0070_p1f_defaults[] =
+
+{
+	7, 0x02,
+		0x0008,
+		0x0000,
+		0x0000,
+		0x0000,
+		0x0000,
+		0x0002,
+		0x0100,
+
+	3, 0x0d,
+		0x0d80,
+		0x0001,
+		0x0000,
+
+	4, 0x11,
+		0x0000,
+		0x0103,
+		0x0000,
+		0x0000,
+
+	3, 0x16,
+		0x0004 | 0x0040,
+		0x0030,
+		0x07ff,
+
+	6, 0x1b,
+		0x4112,
+		0xff00,
+		0xc07f,
+		0x0000,
+		0x0180,
+		0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
+
+	0,
+};
+
+static void dib0070_wbd_calibration(struct dib0070_state *state)
+{
+	u16 wbd_offs;
+	dib0070_write_reg(state, 0x0f, 0x6d81);
+	dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
+	msleep(9);
+	wbd_offs = dib0070_read_reg(state, 0x19);
+	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);
+}
+
+u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	return st->wbd_ff_offset;
+}
+
+EXPORT_SYMBOL(dib0070_wbd_offset);
+static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+    u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
+	dprintk( "CTRL_LO5: 0x%x", lo5);
+	return dib0070_write_reg(state, 0x15, lo5);
+}
+
+#define pgm_read_word(w) (*w)
+static int dib0070_reset(struct dib0070_state *state)
+{
+	u16 l, r, *n;
+
+	HARD_RESET(state);
+
+
+#ifndef FORCE_SBAND_TUNER
+	if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
+		state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
+	else
+#endif
+		state->revision = DIB0070S_P1A;
+
+	/* P1F or not */
+	dprintk( "Revision: %x", state->revision);
+
+	if (state->revision == DIB0070_P1D) {
+		dprintk( "Error: this driver is not to be used meant for P1D or earlier");
+		return -EINVAL;
+	}
+
+	n = (u16 *) dib0070_p1f_defaults;
+	l = pgm_read_word(n++);
+	while (l) {
+		r = pgm_read_word(n++);
+		do {
+			dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
+			r++;
+		} while (--l);
+		l = pgm_read_word(n++);
+	}
+
+	if (state->cfg->force_crystal_mode != 0)
+		r = state->cfg->force_crystal_mode;
+	else if (state->cfg->clock_khz >= 24000)
+		r = 1;
+	else
+		r = 2;
+
+	r |= state->cfg->osc_buffer_state << 3;
+
+	dib0070_write_reg(state, 0x10, r);
+	dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4));
+
+	if (state->cfg->invert_iq) {
+		r = dib0070_read_reg(state, 0x02) & 0xffdf;
+		dib0070_write_reg(state, 0x02, r | (1 << 5));
+	}
+
+
+	if (state->revision == DIB0070S_P1A)
+		dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1);
+	else
+		dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0);
+
+	dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
+	return 0;
+}
+
+
+static int dib0070_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static struct dvb_tuner_ops dib0070_ops = {
+	.info = {
+		.name           = "DiBcom DiB0070",
+		.frequency_min  =  45000000,
+		.frequency_max  = 860000000,
+		.frequency_step =      1000,
+	},
+	.release       = dib0070_release,
+
+	.init          = dib0070_wakeup,
+	.sleep         = dib0070_sleep,
+	.set_params    = dib0070_tune_digital,
+//	.get_frequency = dib0070_get_frequency,
+//	.get_bandwidth = dib0070_get_bandwidth
+};
+
+struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
+{
+	struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->cfg = cfg;
+	state->i2c = i2c;
+	state->fe  = fe;
+	fe->tuner_priv = state;
+
+	if (dib0070_reset(state) != 0)
+		goto free_mem;
+
+	dib0070_wbd_calibration(state);
+
+	printk(KERN_INFO "DiB0070: successfully identified\n");
+	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = state;
+	return fe;
+
+free_mem:
+	kfree(state);
+	fe->tuner_priv = NULL;
+	return NULL;
+}
+EXPORT_SYMBOL(dib0070_attach);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
+MODULE_LICENSE("GPL");

+ 44 - 0
drivers/media/dvb/frontends/dib0070.h

@@ -0,0 +1,44 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ */
+#ifndef DIB0070_H
+#define DIB0070_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+#define DEFAULT_DIB0070_I2C_ADDRESS 0x60
+
+struct dib0070_config {
+	u8 i2c_address;
+
+	/* tuner pins controlled externally */
+	int (*reset) (struct dvb_frontend *, int);
+	int (*sleep) (struct dvb_frontend *, int);
+
+	/*  offset in kHz */
+	int freq_offset_khz_uhf;
+	int freq_offset_khz_vhf;
+
+	u8 osc_buffer_state; /* 0= normal, 1= tri-state */
+	u32  clock_khz;
+	u8 clock_pad_drive; /* (Drive + 1) * 2mA */
+
+	u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */
+
+	u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */
+
+	u8 flip_chip;
+};
+
+extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
+extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
+extern u16 dib0070_wbd_offset(struct dvb_frontend *);
+
+#endif

+ 0 - 1
drivers/media/dvb/frontends/dib3000mb.c

@@ -23,7 +23,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>

+ 121 - 71
drivers/media/dvb/frontends/dib3000mc.c

@@ -1,7 +1,7 @@
 /*
  * Driver for DiBcom DiB3000MC/P-demodulator.
  *
- * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/)
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
  * This code is partially based on the previous dib3000mc.c .
@@ -13,10 +13,6 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-//#include <linux/init.h>
-//#include <linux/delay.h>
-//#include <linux/string.h>
-//#include <linux/slab.h>
 
 #include "dvb_frontend.h"
 
@@ -26,7 +22,11 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0)
 
 struct dib3000mc_state {
 	struct dvb_frontend demod;
@@ -42,6 +42,8 @@ struct dib3000mc_state {
 	fe_bandwidth_t current_bandwidth;
 
 	u16 dev_id;
+
+	u8 sfn_workaround_active :1;
 };
 
 static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
@@ -71,7 +73,6 @@ static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
 	return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
 }
 
-
 static int dib3000mc_identify(struct dib3000mc_state *state)
 {
 	u16 value;
@@ -92,7 +93,7 @@ static int dib3000mc_identify(struct dib3000mc_state *state)
 	return 0;
 }
 
-static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
+static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset)
 {
 	u32 timf;
 
@@ -103,7 +104,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw,
 	} else
 		timf = state->timf;
 
-	timf *= (BW_INDEX_TO_KHZ(bw) / 1000);
+	timf *= (bw / 1000);
 
 	if (update_offset) {
 		s16 tim_offs = dib3000mc_read_word(state, 416);
@@ -111,17 +112,17 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw,
 		if (tim_offs &  0x2000)
 			tim_offs -= 0x4000;
 
-		if (nfft == 0)
+		if (nfft == TRANSMISSION_MODE_2K)
 			tim_offs *= 4;
 
 		timf += tim_offs;
-		state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000);
+		state->timf = timf / (bw / 1000);
 	}
 
 	dprintk("timf: %d\n", timf);
 
-	dib3000mc_write_word(state, 23, timf >> 16);
-	dib3000mc_write_word(state, 24, timf & 0xffff);
+	dib3000mc_write_word(state, 23, (u16) (timf >> 16));
+	dib3000mc_write_word(state, 24, (u16) (timf      ) & 0xffff);
 
 	return 0;
 }
@@ -209,31 +210,30 @@ static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
 	return ret;
 }
 
-static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
+static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw)
 {
-	struct dib3000mc_state *state = demod->demodulator_priv;
 	u16 bw_cfg[6] = { 0 };
 	u16 imp_bw_cfg[3] = { 0 };
 	u16 reg;
 
 /* settings here are for 27.7MHz */
 	switch (bw) {
-		case BANDWIDTH_8_MHZ:
+		case 8000:
 			bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
 			imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
 			break;
 
-		case BANDWIDTH_7_MHZ:
+		case 7000:
 			bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
 			imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
 			break;
 
-		case BANDWIDTH_6_MHZ:
+		case 6000:
 			bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
 			imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
 			break;
 
-		case 255 /* BANDWIDTH_5_MHZ */:
+		case 5000:
 			bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
 			imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
 			break;
@@ -257,7 +257,7 @@ static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
 		dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
 
 	// Timing configuration
-	dib3000mc_set_timing(state, 0, bw, 0);
+	dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0);
 
 	return 0;
 }
@@ -276,7 +276,7 @@ static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode,
 	for (i = 58; i < 87; i++)
 		dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
 
-	if (nfft == 1) {
+	if (nfft == TRANSMISSION_MODE_8K) {
 		dib3000mc_write_word(state, 58, 0x3b);
 		dib3000mc_write_word(state, 84, 0x00);
 		dib3000mc_write_word(state, 85, 0x8200);
@@ -376,7 +376,7 @@ static int dib3000mc_init(struct dvb_frontend *demod)
 	// P_search_maxtrial=1
 	dib3000mc_write_word(state, 5, 1);
 
-	dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+	dib3000mc_set_bandwidth(state, 8000);
 
 	// div_lock_mask
 	dib3000mc_write_word(state,  4, 0x814);
@@ -397,7 +397,7 @@ static int dib3000mc_init(struct dvb_frontend *demod)
 	dib3000mc_write_word(state, 180, 0x2FF0);
 
 	// Impulse noise configuration
-	dib3000mc_set_impulse_noise(state, 0, 1);
+	dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K);
 
 	// output mode set-up
 	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
@@ -423,13 +423,13 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
 {
 	u16 cfg[4] = { 0 },reg;
 	switch (qam) {
-		case 0:
+		case QPSK:
 			cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
 			break;
-		case 1:
+		case QAM_16:
 			cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
 			break;
-		case 2:
+		case QAM_64:
 			cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
 			break;
 	}
@@ -437,11 +437,11 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
 		dib3000mc_write_word(state, reg, cfg[reg - 129]);
 }
 
-static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq)
 {
-	u16 tmp;
-
-	dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
+	u16 value;
+    dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+	dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0);
 
 //	if (boost)
 //		dib3000mc_write_word(state, 100, (11 << 6) + 6);
@@ -455,7 +455,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
 	dib3000mc_write_word(state, 26,  0x6680);
 	dib3000mc_write_word(state, 29,  0x1273);
 	dib3000mc_write_word(state, 33,       5);
-	dib3000mc_set_adp_cfg(state, 1);
+	dib3000mc_set_adp_cfg(state, QAM_16);
 	dib3000mc_write_word(state, 133,  15564);
 
 	dib3000mc_write_word(state, 12 , 0x0);
@@ -470,52 +470,98 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
 	dib3000mc_write_word(state, 97,0);
 	dib3000mc_write_word(state, 98,0);
 
-	dib3000mc_set_impulse_noise(state, 0, chan->nfft);
-
-	tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
-	dib3000mc_write_word(state, 0, tmp);
+	dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode);
 
+	value = 0;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+	}
+	switch (ch->u.ofdm.guard_interval) {
+		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
+		default:
+		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
+	}
+	switch (ch->u.ofdm.constellation) {
+		case QPSK:  value |= (0 << 3); break;
+		case QAM_16: value |= (1 << 3); break;
+		default:
+		case QAM_64: value |= (2 << 3); break;
+	}
+	switch (HIERARCHY_1) {
+		case HIERARCHY_2: value |= 2; break;
+		case HIERARCHY_4: value |= 4; break;
+		default:
+		case HIERARCHY_1: value |= 1; break;
+	}
+	dib3000mc_write_word(state, 0, value);
 	dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
 
-	tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
-	if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
-		tmp |= chan->vit_code_rate_hp << 1;
-	else
-		tmp |= chan->vit_code_rate_lp << 1;
-	dib3000mc_write_word(state, 181, tmp);
+	value = 0;
+	if (ch->u.ofdm.hierarchy_information == 1)
+		value |= (1 << 4);
+	if (1 == 1)
+		value |= 1;
+	switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+		case FEC_2_3: value |= (2 << 1); break;
+		case FEC_3_4: value |= (3 << 1); break;
+		case FEC_5_6: value |= (5 << 1); break;
+		case FEC_7_8: value |= (7 << 1); break;
+		default:
+		case FEC_1_2: value |= (1 << 1); break;
+	}
+	dib3000mc_write_word(state, 181, value);
 
-	// diversity synchro delay
-	tmp = dib3000mc_read_word(state, 180) & 0x000f;
-	tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
-	dib3000mc_write_word(state, 180, tmp);
+	// diversity synchro delay add 50% SFN margin
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_8K: value = 256; break;
+		case TRANSMISSION_MODE_2K:
+		default: value = 64; break;
+	}
+	switch (ch->u.ofdm.guard_interval) {
+		case GUARD_INTERVAL_1_16: value *= 2; break;
+		case GUARD_INTERVAL_1_8:  value *= 4; break;
+		case GUARD_INTERVAL_1_4:  value *= 8; break;
+		default:
+		case GUARD_INTERVAL_1_32: value *= 1; break;
+	}
+	value <<= 4;
+	value |= dib3000mc_read_word(state, 180) & 0x000f;
+	dib3000mc_write_word(state, 180, value);
 
 	// restart demod
-	tmp = dib3000mc_read_word(state, 0);
-	dib3000mc_write_word(state, 0, tmp | (1 << 9));
-	dib3000mc_write_word(state, 0, tmp);
+	value = dib3000mc_read_word(state, 0);
+	dib3000mc_write_word(state, 0, value | (1 << 9));
+	dib3000mc_write_word(state, 0, value);
 
 	msleep(30);
 
-	dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
+	dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);
 }
 
-static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan)
 {
 	struct dib3000mc_state *state = demod->demodulator_priv;
 	u16 reg;
 //	u32 val;
-	struct dibx000_ofdm_channel fchan;
+	struct dvb_frontend_parameters schan;
 
-	INIT_OFDM_CHANNEL(&fchan);
-	fchan = *chan;
+	schan = *chan;
 
+	/* TODO what is that ? */
 
 	/* a channel for autosearch */
-	fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
-	fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
-	fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
+	schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+	schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+	schan.u.ofdm.constellation = QAM_64;
+	schan.u.ofdm.code_rate_HP = FEC_2_3;
+	schan.u.ofdm.code_rate_LP = FEC_2_3;
+	schan.u.ofdm.hierarchy_information = 0;
 
-	dib3000mc_set_channel_cfg(state, &fchan, 11);
+	dib3000mc_set_channel_cfg(state, &schan, 11);
 
 	reg = dib3000mc_read_word(state, 0);
 	dib3000mc_write_word(state, 0, reg | (1 << 8));
@@ -539,7 +585,7 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
 	return 0; // still pending
 }
 
-static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
 {
 	struct dib3000mc_state *state = demod->demodulator_priv;
 
@@ -547,11 +593,17 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe
 	dib3000mc_set_channel_cfg(state, ch, 0);
 
 	// activates isi
-	dib3000mc_write_word(state, 29, 0x1073);
-
-	dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
+	if (state->sfn_workaround_active) {
+		dprintk("SFN workaround is active\n");
+		dib3000mc_write_word(state, 29, 0x1273);
+		dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift
+	} else {
+		dib3000mc_write_word(state, 29, 0x1073);
+		dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift
+	}
 
-	if (ch->nfft == 1) {
+	dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation);
+	if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) {
 		dib3000mc_write_word(state, 26, 38528);
 		dib3000mc_write_word(state, 33, 8);
 	} else {
@@ -560,7 +612,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe
 	}
 
 	if (dib3000mc_read_word(state, 509) & 0x80)
-		dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
+		dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1);
 
 	return 0;
 }
@@ -632,13 +684,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib3000mc_state *state = fe->demodulator_priv;
-	struct dibx000_ofdm_channel ch;
-
-	INIT_OFDM_CHANNEL(&ch);
-	FEP2DIB(fep,&ch);
 
 	state->current_bandwidth = fep->u.ofdm.bandwidth;
-	dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+	dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+
+	/* maybe the parameter has been changed */
+	state->sfn_workaround_active = buggy_sfn_workaround;
 
 	if (fe->ops.tuner_ops.set_params) {
 		fe->ops.tuner_ops.set_params(fe, fep);
@@ -651,7 +702,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
 		int i = 100, found;
 
-		dib3000mc_autosearch_start(fe, &ch);
+		dib3000mc_autosearch_start(fe, fep);
 		do {
 			msleep(1);
 			found = dib3000mc_autosearch_is_irq(fe);
@@ -662,13 +713,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 			return 0; // no channel found
 
 		dib3000mc_get_frontend(fe, fep);
-		FEP2DIB(fep,&ch);
 	}
 
 	/* make this a config parameter */
 	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
 
-	return dib3000mc_tune(fe, &ch);
+	return dib3000mc_tune(fe, fep);
 }
 
 static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)

文件差异内容过多而无法显示
+ 451 - 246
drivers/media/dvb/frontends/dib7000m.c


文件差异内容过多而无法显示
+ 614 - 253
drivers/media/dvb/frontends/dib7000p.c


+ 7 - 7
drivers/media/dvb/frontends/dib7000p.h

@@ -9,6 +9,7 @@ struct dib7000p_config {
 	u8 tuner_is_baseband;
 	int (*update_lna) (struct dvb_frontend *, u16 agc_global);
 
+	u8 agc_config_count;
 	struct dibx000_agc_config *agc;
 	struct dibx000_bandwidth_config *bw;
 
@@ -27,20 +28,19 @@ struct dib7000p_config {
 
 	u8 quartz_direct;
 
+	u8 spur_protect;
+
 	int (*agc_control) (struct dvb_frontend *, u8 before);
 };
 
 #define DEFAULT_DIB7000P_I2C_ADDRESS 18
 
 extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
+
 extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
 extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-
-/* TODO
-extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
-extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod);
-extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
-extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod);
-*/
+extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
 
 #endif

+ 10 - 47
drivers/media/dvb/frontends/dibx000_common.h

@@ -111,6 +111,8 @@ struct dibx000_bandwidth_config {
 
 	u32 ifreq;
 	u32 timf;
+
+	u32 xtal_hz;
 };
 
 enum dibx000_adc_states {
@@ -122,56 +124,17 @@ enum dibx000_adc_states {
 	DIBX000_VBG_DISABLE,
 };
 
-#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ  ? 8000 : \
+#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ  ? 8000 : \
 			     (v) == BANDWIDTH_7_MHZ  ? 7000 : \
 			     (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000 )
 
 /* Chip output mode. */
-#define OUTMODE_HIGH_Z                      0
-#define OUTMODE_MPEG2_PAR_GATED_CLK         1
-#define OUTMODE_MPEG2_PAR_CONT_CLK          2
-#define OUTMODE_MPEG2_SERIAL                7
-#define OUTMODE_DIVERSITY                   4
-#define OUTMODE_MPEG2_FIFO                  5
-
-/* I hope I can get rid of the following kludge in the near future */
-struct dibx000_ofdm_channel {
-	u32 RF_kHz;
-	u8  Bw;
-	s16 nfft;
-	s16 guard;
-	s16 nqam;
-	s16 vit_hrch;
-	s16 vit_select_hp;
-	s16 vit_alpha;
-	s16 vit_code_rate_hp;
-	s16 vit_code_rate_lp;
-	u8  intlv_native;
-};
-
-#define FEP2DIB(fep,ch) \
-	(ch)->RF_kHz           = (fep)->frequency / 1000; \
-	(ch)->Bw               = (fep)->u.ofdm.bandwidth; \
-	(ch)->nfft             = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \
-	(ch)->guard            = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \
-	(ch)->nqam             = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \
-	(ch)->vit_hrch         = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \
-	(ch)->vit_select_hp    = 1; \
-	(ch)->vit_alpha        = 1; \
-	(ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \
-	(ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \
-	(ch)->intlv_native     = 1;
-
-#define INIT_OFDM_CHANNEL(ch) do {\
-	(ch)->Bw               = 0;  \
-	(ch)->nfft             = -1; \
-	(ch)->guard            = -1; \
-	(ch)->nqam             = -1; \
-	(ch)->vit_hrch         = -1; \
-	(ch)->vit_select_hp    = -1; \
-	(ch)->vit_alpha        = -1; \
-	(ch)->vit_code_rate_hp = -1; \
-	(ch)->vit_code_rate_lp = -1; \
-} while (0)
+#define OUTMODE_HIGH_Z              0
+#define OUTMODE_MPEG2_PAR_GATED_CLK 1
+#define OUTMODE_MPEG2_PAR_CONT_CLK  2
+#define OUTMODE_MPEG2_SERIAL        7
+#define OUTMODE_DIVERSITY           4
+#define OUTMODE_MPEG2_FIFO          5
+#define OUTMODE_ANALOG_ADC          6
 
 #endif

+ 110 - 37
drivers/media/dvb/frontends/dvb-pll.c

@@ -24,12 +24,48 @@
 
 #include "dvb-pll.h"
 
+struct dvb_pll_priv {
+	/* pll number */
+	int nr;
+
+	/* i2c details */
+	int pll_i2c_address;
+	struct i2c_adapter *i2c;
+
+	/* the PLL descriptor */
+	struct dvb_pll_desc *pll_desc;
+
+	/* cached frequency/bandwidth */
+	u32 frequency;
+	u32 bandwidth;
+};
+
+#define DVB_PLL_MAX 64
+
+static unsigned int dvb_pll_devcount;
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 };
+module_param_array(input, int, NULL, 0644);
+MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)");
+
+static unsigned int id[DVB_PLL_MAX] =
+	{ [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
+module_param_array(id, int, NULL, 0644);
+MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)");
+
+/* ----------------------------------------------------------- */
+
 struct dvb_pll_desc {
 	char *name;
 	u32  min;
 	u32  max;
 	u32  iffreq;
-	void (*set)(u8 *buf, const struct dvb_frontend_parameters *params);
+	void (*set)(struct dvb_frontend *fe, u8 *buf,
+		    const struct dvb_frontend_parameters *params);
 	u8   *initdata;
 	u8   *sleepdata;
 	int  count;
@@ -89,7 +125,7 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
 	},
 };
 
-static void thomson_dtt759x_bw(u8 *buf,
+static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf,
 			       const struct dvb_frontend_parameters *params)
 {
 	if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
@@ -210,7 +246,8 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
 /* Philips TDA6650/TDA6651
  * used in Panasonic ENV77H11D5
  */
-static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void tda665x_bw(struct dvb_frontend *fe, u8 *buf,
+		       const struct dvb_frontend_parameters *params)
 {
 	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
 		buf[3] |= 0x08;
@@ -243,7 +280,8 @@ static struct dvb_pll_desc dvb_pll_tda665x = {
 /* Infineon TUA6034
  * used in LG TDTP E102P
  */
-static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void tua6034_bw(struct dvb_frontend *fe, u8 *buf,
+		       const struct dvb_frontend_parameters *params)
 {
 	if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
 		buf[3] |= 0x08;
@@ -283,7 +321,8 @@ static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
 /* Philips FMD1216ME
  * used in Medion Hybrid PCMCIA card and USB Box
  */
-static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf,
+			 const struct dvb_frontend_parameters *params)
 {
 	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
 	    params->frequency >= 158870000)
@@ -313,7 +352,8 @@ static struct dvb_pll_desc dvb_pll_fmd1216me = {
 /* ALPS TDED4
  * used in Nebula-Cards and USB boxes
  */
-static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void tded4_bw(struct dvb_frontend *fe, u8 *buf,
+		     const struct dvb_frontend_parameters *params)
 {
 	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
 		buf[3] |= 0x04;
@@ -354,16 +394,35 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = {
 /* Philips TUV1236D
  * used in ATI HDTV Wonder
  */
-static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params)
+static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf,
+			const struct dvb_frontend_parameters *params)
 {
-	switch (params->u.vsb.modulation) {
-		case QAM_64:
-		case QAM_256:
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	unsigned int new_rf = input[priv->nr];
+
+	if ((new_rf == 0) || (new_rf > 2)) {
+		switch (params->u.vsb.modulation) {
+			case QAM_64:
+			case QAM_256:
+				new_rf = 1;
+				break;
+			case VSB_8:
+			default:
+				new_rf = 2;
+		}
+	}
+
+	switch (new_rf) {
+		case 1:
 			buf[3] |= 0x08;
 			break;
-		case VSB_8:
-		default:
+		case 2:
 			buf[3] &= ~0x08;
+			break;
+		default:
+			printk(KERN_WARNING
+			       "%s: unhandled rf input selection: %d",
+			       __FUNCTION__, new_rf);
 	}
 }
 
@@ -420,7 +479,8 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
 /*
  * Philips TD1316 Tuner.
  */
-static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void td1316_bw(struct dvb_frontend *fe, u8 *buf,
+		      const struct dvb_frontend_parameters *params)
 {
 	u8 band;
 
@@ -474,7 +534,8 @@ static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
 	}
 };
 
-static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void opera1_bw(struct dvb_frontend *fe, u8 *buf,
+		      const struct dvb_frontend_parameters *params)
 {
 	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
 		buf[2] |= 0x08;
@@ -545,31 +606,14 @@ static struct dvb_pll_desc *pll_list[] = {
 	[DVB_PLL_FCV1236D]               = &dvb_pll_fcv1236d,
 };
 
-/* ----------------------------------------------------------- */
-
-struct dvb_pll_priv {
-	/* i2c details */
-	int pll_i2c_address;
-	struct i2c_adapter *i2c;
-
-	/* the PLL descriptor */
-	struct dvb_pll_desc *pll_desc;
-
-	/* cached frequency/bandwidth */
-	u32 frequency;
-	u32 bandwidth;
-};
-
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
-static int debug = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
 			     const struct dvb_frontend_parameters *params)
 {
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	struct dvb_pll_desc *desc = priv->pll_desc;
 	u32 div;
 	int i;
 
@@ -597,7 +641,7 @@ static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 	buf[3] = desc->entries[i].cb;
 
 	if (desc->set)
-		desc->set(buf, params);
+		desc->set(fe, buf, params);
 
 	if (debug)
 		printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -654,7 +698,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
 	if (priv->i2c == NULL)
 		return -EINVAL;
 
-	if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0)
+	if ((result = dvb_pll_configure(fe, buf, params)) < 0)
 		return result;
 	else
 		frequency = result;
@@ -682,7 +726,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
 	if (buf_len < 5)
 		return -EINVAL;
 
-	if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0)
+	if ((result = dvb_pll_configure(fe, buf+1, params)) < 0)
 		return result;
 	else
 		frequency = result;
@@ -755,6 +799,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
 	int ret;
 	struct dvb_pll_desc *desc;
 
+	if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
+	    (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
+		pll_desc_id = id[dvb_pll_devcount];
+
 	BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
 
 	desc = pll_list[pll_desc_id];
@@ -777,6 +825,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
 	priv->pll_i2c_address = pll_addr;
 	priv->i2c = i2c;
 	priv->pll_desc = desc;
+	priv->nr = dvb_pll_devcount++;
 
 	memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
 	       sizeof(struct dvb_tuner_ops));
@@ -791,6 +840,30 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
 		fe->ops.tuner_ops.sleep = NULL;
 
 	fe->tuner_priv = priv;
+
+	if ((debug) || (id[priv->nr] == pll_desc_id)) {
+		printk("dvb-pll[%d]", priv->nr);
+		if (i2c != NULL)
+			printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+		printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name,
+		       id[priv->nr] == pll_desc_id ?
+				"insmod option" : "autodetected");
+	}
+	if ((debug) || (input[priv->nr] > 0)) {
+		printk("dvb-pll[%d]", priv->nr);
+		if (i2c != NULL)
+			printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+		printk(": tuner rf input will be ");
+		switch (input[priv->nr]) {
+		case 0:
+			printk("autoselected\n");
+			break;
+		default:
+			printk("set to input %d (insmod option)\n",
+			       input[priv->nr]);
+		}
+	}
+
 	return fe;
 }
 EXPORT_SYMBOL(dvb_pll_attach);

+ 0 - 1
drivers/media/dvb/frontends/dvb_dummy_fe.c

@@ -20,7 +20,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>

+ 0 - 1
drivers/media/dvb/frontends/isl6421.c

@@ -29,7 +29,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 

+ 0 - 1
drivers/media/dvb/frontends/l64781.c

@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include "dvb_frontend.h"

+ 0 - 1
drivers/media/dvb/frontends/lgdt330x.c

@@ -35,7 +35,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>

+ 0 - 1
drivers/media/dvb/frontends/lnbp21.c

@@ -28,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 

+ 0 - 1
drivers/media/dvb/frontends/mt2060.c

@@ -22,7 +22,6 @@
 /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/dvb/frontend.h>
 #include <linux/i2c.h>

+ 314 - 0
drivers/media/dvb/frontends/mt2131.c

@@ -0,0 +1,314 @@
+/*
+ *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2006 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/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "mt2131.h"
+#include "mt2131_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, "mt2131", ## arg)
+
+static u8 mt2131_config1[] = {
+	0x01,
+	0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88,
+	0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32,
+	0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80,
+	0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00
+};
+
+static u8 mt2131_config2[] = {
+	0x10,
+	0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04
+};
+
+static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address, .flags = 0,
+		  .buf = &reg, .len = 1 },
+		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
+		  .buf = val,  .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "mt2131 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0,
+			       .buf = buf, .len = 2 };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mt2131 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mt2131_writeregs(struct mt2131_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_WARNING "mt2131 I2C write failed (len=%i)\n",
+		       (int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mt2131_set_params(struct dvb_frontend *fe,
+			     struct dvb_frontend_parameters *params)
+{
+	struct mt2131_priv *priv;
+	int ret=0, i;
+	u32 freq;
+	u8  if_band_center;
+	u32 f_lo1, f_lo2;
+	u32 div1, num1, div2, num2;
+	u8  b[8];
+	u8 lockval = 0;
+
+	priv = fe->tuner_priv;
+	if (fe->ops.info.type == FE_OFDM)
+		priv->bandwidth = params->u.ofdm.bandwidth;
+	else
+		priv->bandwidth = 0;
+
+	freq = params->frequency / 1000;  // Hz -> kHz
+	dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq);
+
+	f_lo1 = freq + MT2131_IF1 * 1000;
+	f_lo1 = (f_lo1 / 250) * 250;
+	f_lo2 = f_lo1 - freq - MT2131_IF2;
+
+	priv->frequency =  (f_lo1 - f_lo2 - MT2131_IF2) * 1000,
+
+	/* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */
+	num1 = f_lo1 * 64 / (MT2131_FREF / 128);
+	div1 = num1 / 8192;
+	num1 &= 0x1fff;
+
+	/* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */
+	num2 = f_lo2 * 64 / (MT2131_FREF / 128);
+	div2 = num2 / 8192;
+	num2 &= 0x1fff;
+
+	if (freq <=   82500) if_band_center = 0x00; else
+	if (freq <=  137500) if_band_center = 0x01; else
+	if (freq <=  192500) if_band_center = 0x02; else
+	if (freq <=  247500) if_band_center = 0x03; else
+	if (freq <=  302500) if_band_center = 0x04; else
+	if (freq <=  357500) if_band_center = 0x05; else
+	if (freq <=  412500) if_band_center = 0x06; else
+	if (freq <=  467500) if_band_center = 0x07; else
+	if (freq <=  522500) if_band_center = 0x08; else
+	if (freq <=  577500) if_band_center = 0x09; else
+	if (freq <=  632500) if_band_center = 0x0A; else
+	if (freq <=  687500) if_band_center = 0x0B; else
+	if (freq <=  742500) if_band_center = 0x0C; else
+	if (freq <=  797500) if_band_center = 0x0D; else
+	if (freq <=  852500) if_band_center = 0x0E; else
+	if (freq <=  907500) if_band_center = 0x0F; else
+	if (freq <=  962500) if_band_center = 0x10; else
+	if (freq <= 1017500) if_band_center = 0x11; else
+	if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13;
+
+	b[0] = 1;
+	b[1] = (num1 >> 5) & 0xFF;
+	b[2] = (num1 & 0x1F);
+	b[3] = div1;
+	b[4] = (num2 >> 5) & 0xFF;
+	b[5] = num2 & 0x1F;
+	b[6] = div2;
+
+	dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2);
+	dprintk(1, "PLL freq=%dkHz  band=%d\n", (int)freq, (int)if_band_center);
+	dprintk(1, "PLL f_lo1=%dkHz  f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2);
+	dprintk(1, "PLL div1=%d  num1=%d  div2=%d  num2=%d\n",
+		(int)div1, (int)num1, (int)div2, (int)num2);
+	dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n",
+		(int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5],
+		(int)b[6]);
+
+	ret = mt2131_writeregs(priv,b,7);
+	if (ret < 0)
+		return ret;
+
+	mt2131_writereg(priv, 0x0b, if_band_center);
+
+	/* Wait for lock */
+	i = 0;
+	do {
+		mt2131_readreg(priv, 0x08, &lockval);
+		if ((lockval & 0x88) == 0x88)
+			break;
+		msleep(4);
+		i++;
+	} while (i < 10);
+
+	return ret;
+}
+
+static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	u8 lock_status = 0;
+	u8 afc_status = 0;
+
+	*status = 0;
+
+	mt2131_readreg(priv, 0x08, &lock_status);
+	if ((lock_status & 0x88) == 0x88)
+		*status = TUNER_STATUS_LOCKED;
+
+	mt2131_readreg(priv, 0x09, &afc_status);
+	dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",
+		__FUNCTION__, lock_status, afc_status);
+
+	return 0;
+}
+
+static int mt2131_init(struct dvb_frontend *fe)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	int ret;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if ((ret = mt2131_writeregs(priv, mt2131_config1,
+				    sizeof(mt2131_config1))) < 0)
+		return ret;
+
+	mt2131_writereg(priv, 0x0b, 0x09);
+	mt2131_writereg(priv, 0x15, 0x47);
+	mt2131_writereg(priv, 0x07, 0xf2);
+	mt2131_writereg(priv, 0x0b, 0x01);
+
+	if ((ret = mt2131_writeregs(priv, mt2131_config2,
+				    sizeof(mt2131_config2))) < 0)
+		return ret;
+
+	return ret;
+}
+
+static int mt2131_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 mt2131_tuner_ops = {
+	.info = {
+		.name           = "Microtune MT2131",
+		.frequency_min  =  48000000,
+		.frequency_max  = 860000000,
+		.frequency_step =     50000,
+	},
+
+	.release       = mt2131_release,
+	.init          = mt2131_init,
+
+	.set_params    = mt2131_set_params,
+	.get_frequency = mt2131_get_frequency,
+	.get_bandwidth = mt2131_get_bandwidth,
+	.get_status    = mt2131_get_status
+};
+
+struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c,
+				    struct mt2131_config *cfg, u16 if1)
+{
+	struct mt2131_priv *priv = NULL;
+	u8 id = 0;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->bandwidth = 6000000; /* 6MHz */
+	priv->i2c = i2c;
+
+	if (mt2131_readreg(priv, 0, &id) != 0) {
+		kfree(priv);
+		return NULL;
+	}
+	if ( (id != 0x3E) && (id != 0x3F) ) {
+		printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n",
+		       cfg->i2c_address);
+		kfree(priv);
+		return NULL;
+	}
+
+	printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n",
+	       cfg->i2c_address);
+	memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+	return fe;
+}
+EXPORT_SYMBOL(mt2131_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */

+ 54 - 0
drivers/media/dvb/frontends/mt2131.h

@@ -0,0 +1,54 @@
+/*
+ *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2006 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 __MT2131_H__
+#define __MT2131_H__
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2131_config {
+	u8 i2c_address;
+	u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
+};
+
+#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE))
+extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+					  struct i2c_adapter *i2c,
+					  struct mt2131_config *cfg,
+					  u16 if1);
+#else
+static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+						 struct i2c_adapter *i2c,
+						 struct mt2131_config *cfg,
+						 u16 if1)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_TUNER_MT2131 */
+
+#endif /* __MT2131_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */

+ 49 - 0
drivers/media/dvb/frontends/mt2131_priv.h

@@ -0,0 +1,49 @@
+/*
+ *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2006 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 __MT2131_PRIV_H__
+#define __MT2131_PRIV_H__
+
+/* Regs */
+#define MT2131_PWR              0x07
+#define MT2131_UPC_1            0x0b
+#define MT2131_AGC_RL           0x10
+#define MT2131_MISC_2           0x15
+
+/* frequency values in KHz */
+#define MT2131_IF1              1220
+#define MT2131_IF2              44000
+#define MT2131_FREF             16000
+
+struct mt2131_priv {
+	struct mt2131_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+#endif /* __MT2131_PRIV_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */

+ 287 - 0
drivers/media/dvb/frontends/mt2266.c

@@ -0,0 +1,287 @@
+/*
+ *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ *  Copyright (c) 2007 Olivier DANET <odanet@caramail.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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+#include "mt2266.h"
+
+#define I2C_ADDRESS 0x60
+
+#define REG_PART_REV   0
+#define REG_TUNE       1
+#define REG_BAND       6
+#define REG_BANDWIDTH  8
+#define REG_LOCK       0x12
+
+#define PART_REV 0x85
+
+struct mt2266_priv {
+	struct mt2266_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
+
+// Reads a single register
+static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
+	};
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "MT2266 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a single register
+static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
+	};
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "MT2266 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a set of consecutive registers
+static int mt2266_writeregs(struct mt2266_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_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Initialisation sequences
+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 };
+
+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_6mhz[] = {
+	REG_BANDWIDTH,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 };
+
+#define FREF 30000       // Quartz oscillator 30 MHz
+
+static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct mt2266_priv *priv;
+	int ret=0;
+	u32 freq;
+	u32 tune;
+	u8  lnaband;
+	u8  b[10];
+	int i;
+
+	priv = fe->tuner_priv;
+
+	mt2266_writereg(priv,0x17,0x6d);
+	mt2266_writereg(priv,0x1c,0xff);
+
+	freq = params->frequency / 1000; // Hz -> kHz
+	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));
+
+	b[0] = REG_TUNE;
+	b[1] = (tune >> 8) & 0x1F;
+	b[2] = tune & 0xFF;
+	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);
+
+	//Waits for pll lock or timeout
+	i = 0;
+	do {
+		mt2266_readreg(priv,REG_LOCK,b);
+		if ((b[0] & 0x40)==0x40)
+			break;
+		msleep(10);
+		i++;
+	} while (i<10);
+	dprintk("Lock when i=%i",(int)i);
+	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));
+
+	msleep(25);
+	mt2266_writereg(priv,0x17,0x6d);
+	mt2266_writereg(priv,0x1c,0x00);
+	msleep(75);
+	mt2266_writereg(priv,0x17,0x6d);
+	mt2266_writereg(priv,0x1c,0xff);
+}
+
+static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int mt2266_init(struct dvb_frontend *fe)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	mt2266_writereg(priv,0x17,0x6d);
+	mt2266_writereg(priv,0x1c,0xff);
+	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);
+	return 0;
+}
+
+static int mt2266_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mt2266_tuner_ops = {
+	.info = {
+		.name           = "Microtune MT2266",
+		.frequency_min  = 470000000,
+		.frequency_max  = 860000000,
+		.frequency_step =     50000,
+	},
+	.release       = mt2266_release,
+	.init          = mt2266_init,
+	.sleep         = mt2266_sleep,
+	.set_params    = mt2266_set_params,
+	.get_frequency = mt2266_get_frequency,
+	.get_bandwidth = mt2266_get_bandwidth
+};
+
+struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
+{
+	struct mt2266_priv *priv = NULL;
+	u8 id = 0;
+
+	priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg      = cfg;
+	priv->i2c      = i2c;
+
+	if (mt2266_readreg(priv,0,&id) != 0) {
+		kfree(priv);
+		return NULL;
+	}
+	if (id != PART_REV) {
+		kfree(priv);
+		return NULL;
+	}
+	printk(KERN_INFO "MT2266: successfully identified\n");
+	memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+	mt2266_calibrate(priv);
+	return fe;
+}
+EXPORT_SYMBOL(mt2266_attach);
+
+MODULE_AUTHOR("Olivier DANET");
+MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
+MODULE_LICENSE("GPL");

+ 37 - 0
drivers/media/dvb/frontends/mt2266.h

@@ -0,0 +1,37 @@
+/*
+ *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ *  Copyright (c) 2007 Olivier DANET <odanet@caramail.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.
+ */
+
+#ifndef MT2266_H
+#define MT2266_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2266_config {
+	u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE))
+extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
+#else
+static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TUNER_MT2266
+
+#endif

+ 0 - 1
drivers/media/dvb/frontends/mt312.c

@@ -28,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 

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

@@ -32,7 +32,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>

+ 0 - 1
drivers/media/dvb/frontends/nxt200x.c

@@ -44,7 +44,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 

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

@@ -36,7 +36,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>

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

@@ -32,7 +32,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/string.h>

+ 729 - 0
drivers/media/dvb/frontends/s5h1409.c

@@ -0,0 +1,729 @@
+/*
+    Samsung S5H1409 VSB/QAM demodulator driver
+
+    Copyright (C) 2006 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "s5h1409.h"
+
+struct s5h1409_state {
+
+	struct i2c_adapter* i2c;
+
+	/* configuration settings */
+	const struct s5h1409_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* previous uncorrected block counter */
+	fe_modulation_t current_modulation;
+
+	u32 current_frequency;
+};
+
+static int debug = 0;
+#define dprintk	if (debug) printk
+
+/* Register values to initialise the demod, this will set VSB by default */
+static struct init_tab {
+	u8	reg;
+	u16	data;
+} init_tab[] = {
+	{ 0x00, 0x0071, },
+	{ 0x01, 0x3213, },
+	{ 0x09, 0x0025, },
+	{ 0x1c, 0x001d, },
+	{ 0x1f, 0x002d, },
+	{ 0x20, 0x001d, },
+	{ 0x22, 0x0022, },
+	{ 0x23, 0x0020, },
+	{ 0x29, 0x110f, },
+	{ 0x2a, 0x10b4, },
+	{ 0x2b, 0x10ae, },
+	{ 0x2c, 0x0031, },
+	{ 0x31, 0x010d, },
+	{ 0x32, 0x0100, },
+	{ 0x44, 0x0510, },
+	{ 0x54, 0x0104, },
+	{ 0x58, 0x2222, },
+	{ 0x59, 0x1162, },
+	{ 0x5a, 0x3211, },
+	{ 0x5d, 0x0370, },
+	{ 0x5e, 0x0296, },
+	{ 0x61, 0x0010, },
+	{ 0x63, 0x4a00, },
+	{ 0x65, 0x0800, },
+	{ 0x71, 0x0003, },
+	{ 0x72, 0x0470, },
+	{ 0x81, 0x0002, },
+	{ 0x82, 0x0600, },
+	{ 0x86, 0x0002, },
+	{ 0x8a, 0x2c38, },
+	{ 0x8b, 0x2a37, },
+	{ 0x92, 0x302f, },
+	{ 0x93, 0x3332, },
+	{ 0x96, 0x000c, },
+	{ 0x99, 0x0101, },
+	{ 0x9c, 0x2e37, },
+	{ 0x9d, 0x2c37, },
+	{ 0x9e, 0x2c37, },
+	{ 0xab, 0x0100, },
+	{ 0xac, 0x1003, },
+	{ 0xad, 0x103f, },
+	{ 0xe2, 0x0100, },
+	{ 0x28, 0x1010, },
+	{ 0xb1, 0x000e, },
+};
+
+/* VSB SNR lookup table */
+static struct vsb_snr_tab {
+	u16	val;
+	u16	data;
+} vsb_snr_tab[] = {
+	{ 1023, 770, },
+	{  923, 300, },
+	{  918, 295, },
+	{  915, 290, },
+	{  911, 285, },
+	{  906, 280, },
+	{  901, 275, },
+	{  896, 270, },
+	{  891, 265, },
+	{  885, 260, },
+	{  879, 255, },
+	{  873, 250, },
+	{  864, 245, },
+	{  858, 240, },
+	{  850, 235, },
+	{  841, 230, },
+	{  832, 225, },
+	{  823, 220, },
+	{  812, 215, },
+	{  802, 210, },
+	{  788, 205, },
+	{  778, 200, },
+	{  767, 195, },
+	{  753, 190, },
+	{  740, 185, },
+	{  725, 180, },
+	{  707, 175, },
+	{  689, 170, },
+	{  671, 165, },
+	{  656, 160, },
+	{  637, 155, },
+	{  616, 150, },
+	{  542, 145, },
+	{  519, 140, },
+	{  507, 135, },
+	{  497, 130, },
+	{  492, 125, },
+	{  474, 120, },
+	{  300, 111, },
+	{    0,   0, },
+};
+
+/* QAM64 SNR lookup table */
+static struct qam64_snr_tab {
+	u16	val;
+	u16	data;
+} qam64_snr_tab[] = {
+	{   12, 300, },
+	{   15, 290, },
+	{   18, 280, },
+	{   22, 270, },
+	{   23, 268, },
+	{   24, 266, },
+	{   25, 264, },
+	{   27, 262, },
+	{   28, 260, },
+	{   29, 258, },
+	{   30, 256, },
+	{   32, 254, },
+	{   33, 252, },
+	{   34, 250, },
+	{   35, 249, },
+	{   36, 248, },
+	{   37, 247, },
+	{   38, 246, },
+	{   39, 245, },
+	{   40, 244, },
+	{   41, 243, },
+	{   42, 241, },
+	{   43, 240, },
+	{   44, 239, },
+	{   45, 238, },
+	{   46, 237, },
+	{   47, 236, },
+	{   48, 235, },
+	{   49, 234, },
+	{   50, 233, },
+	{   51, 232, },
+	{   52, 231, },
+	{   53, 230, },
+	{   55, 229, },
+	{   56, 228, },
+	{   57, 227, },
+	{   58, 226, },
+	{   59, 225, },
+	{   60, 224, },
+	{   62, 223, },
+	{   63, 222, },
+	{   65, 221, },
+	{   66, 220, },
+	{   68, 219, },
+	{   69, 218, },
+	{   70, 217, },
+	{   72, 216, },
+	{   73, 215, },
+	{   75, 214, },
+	{   76, 213, },
+	{   78, 212, },
+	{   80, 211, },
+	{   81, 210, },
+	{   83, 209, },
+	{   84, 208, },
+	{   85, 207, },
+	{   87, 206, },
+	{   89, 205, },
+	{   91, 204, },
+	{   93, 203, },
+	{   95, 202, },
+	{   96, 201, },
+	{  104, 200, },
+};
+
+/* QAM256 SNR lookup table */
+static struct qam256_snr_tab {
+	u16	val;
+	u16	data;
+} qam256_snr_tab[] = {
+	{   12, 400, },
+	{   13, 390, },
+	{   15, 380, },
+	{   17, 360, },
+	{   19, 350, },
+	{   22, 348, },
+	{   23, 346, },
+	{   24, 344, },
+	{   25, 342, },
+	{   26, 340, },
+	{   27, 336, },
+	{   28, 334, },
+	{   29, 332, },
+	{   30, 330, },
+	{   31, 328, },
+	{   32, 326, },
+	{   33, 325, },
+	{   34, 322, },
+	{   35, 320, },
+	{   37, 318, },
+	{   39, 316, },
+	{   40, 314, },
+	{   41, 312, },
+	{   42, 310, },
+	{   43, 308, },
+	{   46, 306, },
+	{   47, 304, },
+	{   49, 302, },
+	{   51, 300, },
+	{   53, 298, },
+	{   54, 297, },
+	{   55, 296, },
+	{   56, 295, },
+	{   57, 294, },
+	{   59, 293, },
+	{   60, 292, },
+	{   61, 291, },
+	{   63, 290, },
+	{   64, 289, },
+	{   65, 288, },
+	{   66, 287, },
+	{   68, 286, },
+	{   69, 285, },
+	{   71, 284, },
+	{   72, 283, },
+	{   74, 282, },
+	{   75, 281, },
+	{   76, 280, },
+	{   77, 279, },
+	{   78, 278, },
+	{   81, 277, },
+	{   83, 276, },
+	{   84, 275, },
+	{   86, 274, },
+	{   87, 273, },
+	{   89, 272, },
+	{   90, 271, },
+	{   92, 270, },
+	{   93, 269, },
+	{   95, 268, },
+	{   96, 267, },
+	{   98, 266, },
+	{  100, 265, },
+	{  102, 264, },
+	{  104, 263, },
+	{  105, 262, },
+	{  106, 261, },
+	{  110, 260, },
+};
+
+/* 8 bit registers, 16 bit values */
+static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data)
+{
+	int ret;
+	u8 buf [] = { reg, data >> 8,  data & 0xff };
+
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = 0, .buf = buf, .len = 3 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+		       "ret == %i)\n", __FUNCTION__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0, 0 };
+
+	struct i2c_msg msg [] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+		  .buf = b0, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+		  .buf = b1, .len = 2 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+	return (b1[0] << 8) | b1[1];
+}
+
+static int s5h1409_softreset(struct dvb_frontend* fe)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __FUNCTION__);
+
+	s5h1409_writereg(state, 0xf5, 0);
+	s5h1409_writereg(state, 0xf5, 1);
+	return 0;
+}
+
+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 {
+		printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __FUNCTION__);
+
+	if(inverted == 1)
+		return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
+	else
+		return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
+}
+
+static int s5h1409_enable_modulation(struct dvb_frontend* fe,
+				     fe_modulation_t m)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(0x%08x)\n", __FUNCTION__, m);
+
+	switch(m) {
+	case VSB_8:
+		dprintk("%s() VSB_8\n", __FUNCTION__);
+		s5h1409_writereg(state, 0xf4, 0);
+		break;
+	case QAM_64:
+		dprintk("%s() QAM_64\n", __FUNCTION__);
+		s5h1409_writereg(state, 0xf4, 1);
+		s5h1409_writereg(state, 0x85, 0x100);
+		break;
+	case QAM_256:
+		dprintk("%s() QAM_256\n", __FUNCTION__);
+		s5h1409_writereg(state, 0xf4, 1);
+		s5h1409_writereg(state, 0x85, 0x101);
+		break;
+	default:
+		dprintk("%s() Invalid modulation\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	state->current_modulation = m;
+	s5h1409_softreset(fe);
+
+	return 0;
+}
+
+static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+	if (enable)
+		return s5h1409_writereg(state, 0xf3, 1);
+	else
+		return s5h1409_writereg(state, 0xf3, 0);
+}
+
+static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+	if (enable)
+		return s5h1409_writereg(state, 0xe3, 0x1100);
+	else
+		return s5h1409_writereg(state, 0xe3, 0);
+}
+
+static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+	return s5h1409_writereg(state, 0xf2, enable);
+}
+
+static int s5h1409_register_reset(struct dvb_frontend* fe)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __FUNCTION__);
+
+	return s5h1409_writereg(state, 0xfa, 0);
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1409_set_frontend (struct dvb_frontend* fe,
+				 struct dvb_frontend_parameters *p)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(frequency=%d)\n", __FUNCTION__, p->frequency);
+
+	s5h1409_softreset(fe);
+
+	state->current_frequency = p->frequency;
+
+	s5h1409_enable_modulation(fe, p->u.vsb.modulation);
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int s5h1409_init (struct dvb_frontend* fe)
+{
+	int i;
+
+	struct s5h1409_state* state = fe->demodulator_priv;
+	dprintk("%s()\n", __FUNCTION__);
+
+	s5h1409_sleep(fe, 0);
+	s5h1409_register_reset(fe);
+
+	for (i=0; i < ARRAY_SIZE(init_tab); i++)
+		s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
+
+	/* The datasheet says that after initialisation, VSB is default */
+	state->current_modulation = VSB_8;
+
+	if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
+		s5h1409_writereg(state, 0xab, 0x100); /* Serial */
+	else
+		s5h1409_writereg(state, 0xab, 0x0); /* Parallel */
+
+	s5h1409_set_spectralinversion(fe, state->config->inversion);
+	s5h1409_set_if_freq(fe, state->config->if_freq);
+	s5h1409_set_gpio(fe, state->config->gpio);
+	s5h1409_softreset(fe);
+
+	/* Note: Leaving the I2C gate open here. */
+	s5h1409_i2c_gate_ctrl(fe, 1);
+
+	return 0;
+}
+
+static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+	u16 reg;
+	u32 tuner_status = 0;
+
+	*status = 0;
+
+	/* Get the demodulator status */
+	reg = s5h1409_readreg(state, 0xf1);
+	if(reg & 0x1000)
+		*status |= FE_HAS_VITERBI;
+	if(reg & 0x8000)
+		*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+
+	switch(state->config->status_mode) {
+	case S5H1409_DEMODLOCKING:
+		if (*status & FE_HAS_VITERBI)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	case S5H1409_TUNERLOCKING:
+		/* Get the tuner status */
+		if (fe->ops.tuner_ops.get_status) {
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+
+			fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (tuner_status)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	}
+
+	dprintk("%s() status 0x%08x\n", __FUNCTION__, *status);
+
+	return 0;
+}
+
+static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __FUNCTION__);
+
+	for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+		if (v < qam256_snr_tab[i].val) {
+			*snr = qam256_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __FUNCTION__);
+
+	for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+		if (v < qam64_snr_tab[i].val) {
+			*snr = qam64_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __FUNCTION__);
+
+	for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+		if (v > vsb_snr_tab[i].val) {
+			*snr = vsb_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	dprintk("%s() snr=%d\n", __FUNCTION__, *snr);
+	return ret;
+}
+
+static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+	u16 reg;
+	dprintk("%s()\n", __FUNCTION__);
+
+	reg = s5h1409_readreg(state, 0xf1) & 0x1ff;
+
+	switch(state->current_modulation) {
+	case QAM_64:
+		return s5h1409_qam64_lookup_snr(fe, snr, reg);
+	case QAM_256:
+		return s5h1409_qam256_lookup_snr(fe, snr, reg);
+	case VSB_8:
+		return s5h1409_vsb_lookup_snr(fe, snr, reg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int s5h1409_read_signal_strength(struct dvb_frontend* fe,
+					u16* signal_strength)
+{
+	return s5h1409_read_snr(fe, signal_strength);
+}
+
+static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	*ucblocks = s5h1409_readreg(state, 0xb5);
+
+	return 0;
+}
+
+static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	return s5h1409_read_ucblocks(fe, ber);
+}
+
+static int s5h1409_get_frontend(struct dvb_frontend* fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	p->frequency = state->current_frequency;
+	p->u.vsb.modulation = state->current_modulation;
+
+	return 0;
+}
+
+static int s5h1409_get_tune_settings(struct dvb_frontend* fe,
+				     struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void s5h1409_release(struct dvb_frontend* fe)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1409_ops;
+
+struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct s5h1409_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->current_modulation = 0;
+
+	/* check if the demod exists */
+	if (s5h1409_readreg(state, 0x04) != 0x0066)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &s5h1409_ops,
+	       sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	/* Note: Leaving the I2C gate open here. */
+	s5h1409_writereg(state, 0xf3, 1);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops s5h1409_ops = {
+
+	.info = {
+		.name			= "Samsung S5H1409 QAM/8VSB Frontend",
+		.type			= FE_ATSC,
+		.frequency_min		= 54000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.init                 = s5h1409_init,
+	.i2c_gate_ctrl        = s5h1409_i2c_gate_ctrl,
+	.set_frontend         = s5h1409_set_frontend,
+	.get_frontend         = s5h1409_get_frontend,
+	.get_tune_settings    = s5h1409_get_tune_settings,
+	.read_status          = s5h1409_read_status,
+	.read_ber             = s5h1409_read_ber,
+	.read_signal_strength = s5h1409_read_signal_strength,
+	.read_snr             = s5h1409_read_snr,
+	.read_ucblocks        = s5h1409_read_ucblocks,
+	.release              = s5h1409_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(s5h1409_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */

+ 73 - 0
drivers/media/dvb/frontends/s5h1409.h

@@ -0,0 +1,73 @@
+/*
+    Samsung S5H1409 VSB/QAM demodulator driver
+
+    Copyright (C) 2006 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 __S5H1409_H__
+#define __S5H1409_H__
+
+#include <linux/dvb/frontend.h>
+
+struct s5h1409_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* serial/parallel output */
+#define S5H1409_PARALLEL_OUTPUT 0
+#define S5H1409_SERIAL_OUTPUT   1
+	u8 output_mode;
+
+	/* GPIO Setting */
+#define S5H1409_GPIO_OFF 0
+#define S5H1409_GPIO_ON  1
+	u8 gpio;
+
+	/* IF Freq in KHz */
+	u16 if_freq;
+
+	/* Spectral Inversion */
+#define S5H1409_INVERSION_OFF 0
+#define S5H1409_INVERSION_ON  1
+	u8 inversion;
+
+	/* Return lock status based on tuner lock, or demod lock */
+#define S5H1409_TUNERLOCKING 0
+#define S5H1409_DEMODLOCKING 1
+	u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
+extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+						  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_S5H1409 */
+
+#endif /* __S5H1409_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */

+ 0 - 1
drivers/media/dvb/frontends/sp8870.c

@@ -29,7 +29,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/delay.h>

+ 0 - 1
drivers/media/dvb/frontends/sp887x.c

@@ -12,7 +12,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/string.h>

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

@@ -680,8 +680,8 @@ static struct dvb_frontend_ops stv0297_ops = {
 	.info = {
 		 .name = "ST STV0297 DVB-C",
 		 .type = FE_QAM,
-		 .frequency_min = 64000000,
-		 .frequency_max = 1300000000,
+		 .frequency_min = 47000000,
+		 .frequency_max = 862000000,
 		 .frequency_stepsize = 62500,
 		 .symbol_rate_min = 870000,
 		 .symbol_rate_max = 11700000,

+ 0 - 1
drivers/media/dvb/frontends/stv0299.c

@@ -45,7 +45,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>

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

@@ -439,8 +439,8 @@ static struct dvb_frontend_ops tda10021_ops = {
 		.name = "Philips TDA10021 DVB-C",
 		.type = FE_QAM,
 		.frequency_stepsize = 62500,
-		.frequency_min = 51000000,
-		.frequency_max = 858000000,
+		.frequency_min = 47000000,
+		.frequency_max = 862000000,
 		.symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
 		.symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
 	#if 0

+ 2 - 8
drivers/media/dvb/frontends/tda10023.c

@@ -215,12 +215,6 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
 	s16 SFIL=0;
 	u16 NDEC = 0;
 
-	if (sr > (SYSCLK/(2*4)))
-		sr=SYSCLK/(2*4);
-
-	if (sr<870000)
-		sr=870000;
-
 	if (sr < (u32)(SYSCLK/98.40)) {
 		NDEC=3;
 		SFIL=1;
@@ -506,8 +500,8 @@ static struct dvb_frontend_ops tda10023_ops = {
 		.name = "Philips TDA10023 DVB-C",
 		.type = FE_QAM,
 		.frequency_stepsize = 62500,
-		.frequency_min = 51000000,
-		.frequency_max = 858000000,
+		.frequency_min = 47000000,
+		.frequency_max = 862000000,
 		.symbol_rate_min = (SYSCLK/2)/64,     /* SACLK/64 == (SYSCLK/2)/64 */
 		.symbol_rate_max = (SYSCLK/2)/4,      /* SACLK/4 */
 		.caps = 0x400 | //FE_CAN_QAM_4

+ 0 - 1
drivers/media/dvb/frontends/tda1004x.c

@@ -31,7 +31,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/jiffies.h>
 #include <linux/string.h>

+ 0 - 1
drivers/media/dvb/frontends/tda10086.c

@@ -22,7 +22,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/jiffies.h>
 #include <linux/string.h>

+ 4 - 5
drivers/media/dvb/frontends/tda8083.c

@@ -27,7 +27,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
@@ -443,12 +442,12 @@ static struct dvb_frontend_ops tda8083_ops = {
 	.info = {
 		.name			= "Philips TDA8083 DVB-S",
 		.type			= FE_QPSK,
-		.frequency_min		= 950000,     /* FIXME: guessed! */
-		.frequency_max		= 1400000,    /* FIXME: guessed! */
+		.frequency_min		= 920000,     /* TDA8060 */
+		.frequency_max		= 2200000,    /* TDA8060 */
 		.frequency_stepsize	= 125,   /* kHz for QPSK frontends */
 	/*      .frequency_tolerance	= ???,*/
-		.symbol_rate_min	= 1000000,   /* FIXME: guessed! */
-		.symbol_rate_max	= 45000000,  /* FIXME: guessed! */
+		.symbol_rate_min	= 12000000,
+		.symbol_rate_max	= 30000000,
 	/*      .symbol_rate_tolerance	= ???,*/
 		.caps = FE_CAN_INVERSION_AUTO |
 			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |

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

@@ -410,8 +410,8 @@ static struct dvb_frontend_ops ves1820_ops = {
 		.name = "VLSI VES1820 DVB-C",
 		.type = FE_QAM,
 		.frequency_stepsize = 62500,
-		.frequency_min = 51000000,
-		.frequency_max = 858000000,
+		.frequency_min = 47000000,
+		.frequency_max = 862000000,
 		.caps = FE_CAN_QAM_16 |
 			FE_CAN_QAM_32 |
 			FE_CAN_QAM_64 |

+ 0 - 1
drivers/media/dvb/frontends/zl10353.c

@@ -21,7 +21,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>

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

@@ -40,7 +40,6 @@
 #include <linux/smp_lock.h>
 
 #include <linux/kernel.h>
-#include <linux/moduleparam.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -1543,7 +1542,7 @@ static int get_firmware(struct av7110* av7110)
 	}
 
 	/* check if the firmware is available */
-	av7110->bin_fw = (unsigned char *) vmalloc(fw->size);
+	av7110->bin_fw = vmalloc(fw->size);
 	if (NULL == av7110->bin_fw) {
 		dprintk(1, "out of memory\n");
 		release_firmware(fw);

+ 14 - 14
drivers/media/dvb/ttpci/av7110_hw.c

@@ -978,24 +978,24 @@ static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 ble
 
 static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
 {
-       int i;
-       int length = last - first + 1;
+	int i;
+	int length = last - first + 1;
 
-       if (length * 4 > DATA_BUFF3_SIZE)
-	       return -EINVAL;
+	if (length * 4 > DATA_BUFF3_SIZE)
+		return -EINVAL;
 
-       for (i = 0; i < length; i++) {
-	       u32 color, blend, yuv;
+	for (i = 0; i < length; i++) {
+		u32 color, blend, yuv;
 
-	       if (get_user(color, colors + i))
-		       return -EFAULT;
-	       blend = (color & 0xF0000000) >> 4;
-	       yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
+		if (get_user(color, colors + i))
+			return -EFAULT;
+		blend = (color & 0xF0000000) >> 4;
+		yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
 				     (color >> 16) & 0xFF) | blend : 0;
-	       yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
-	       wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
-       }
-       return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
+		yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
+		wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
+	}
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
 			    av7110->osdwin,
 			    bpp2pal[av7110->osdbpp[av7110->osdwin]],
 			    first, last);

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

@@ -25,7 +25,6 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
 #include <asm/bitops.h>
@@ -280,7 +279,7 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
 	if (count < size)
 		return -EINVAL;
 
-	page = (char *) vmalloc(size);
+	page = vmalloc(size);
 	if (!page)
 		return -ENOMEM;
 

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

@@ -129,23 +129,25 @@ static struct v4l2_input inputs[4] = {
 
 static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
 {
+	struct av7110 *av7110 = dev->ext_priv;
 	u8 buf[] = { 0x00, reg, data };
 	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
 
 	dprintk(4, "dev: %p\n", dev);
 
-	if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
+	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
 		return -1;
 	return 0;
 }
 
 static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
 {
+	struct av7110 *av7110 = dev->ext_priv;
 	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
 
 	dprintk(4, "dev: %p\n", dev);
 
-	if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
+	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
 		return -1;
 	return 0;
 }

+ 1 - 1
drivers/media/dvb/ttpci/budget-av.c

@@ -1232,7 +1232,7 @@ static struct saa7146_ext_vv vv_data = {
 	.capabilities = 0,	// perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
 	.flags = 0,
 	.stds = &standard[0],
-	.num_stds = sizeof(standard) / sizeof(struct saa7146_standard),
+	.num_stds = ARRAY_SIZE(standard),
 	.ioctls = &ioctls[0],
 	.ioctl = av_ioctl,
 };

+ 1 - 1
drivers/media/dvb/ttpci/budget-ci.c

@@ -214,7 +214,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 	case 0x100f:
 	case 0x1011:
 	case 0x1012:
-	case 0x1017:
 		/* The hauppauge keymap is a superset of these remotes */
 		ir_input_init(input_dev, &budget_ci->ir.state,
 			      IR_TYPE_RC5, ir_codes_hauppauge_new);
@@ -225,6 +224,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 			budget_ci->ir.rc5_device = rc5_device;
 		break;
 	case 0x1010:
+	case 0x1017:
 		/* for the Technotrend 1500 bundled remote */
 		ir_input_init(input_dev, &budget_ci->ir.state,
 			      IR_TYPE_RC5, ir_codes_tt_1500);

+ 0 - 1
drivers/media/dvb/ttpci/budget-core.c

@@ -34,7 +34,6 @@
  * the project's page is at http://www.linuxtv.org/dvb/
  */
 
-#include <linux/moduleparam.h>
 
 #include "budget.h"
 #include "ttpci-eeprom.h"

+ 0 - 1
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c

@@ -13,7 +13,6 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/usb.h>
 #include <linux/delay.h>
 #include <linux/time.h>

+ 0 - 1
drivers/media/dvb/ttusb-dec/ttusb_dec.c

@@ -22,7 +22,6 @@
 
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>

+ 20 - 4
drivers/media/radio/Kconfig

@@ -111,11 +111,16 @@ config RADIO_AZTECH_PORT
 	  jumper sets the card to 0x358.
 
 config RADIO_GEMTEK
-	tristate "GemTek Radio Card support"
+	tristate "GemTek Radio card (or compatible) support"
 	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have this FM radio card, and then fill in the
-	  port address below.
+	  I/O port address and settings below. The following cards either have
+	  GemTek Radio tuner or are rebranded GemTek Radio cards:
+
+	  - Sound Vision 16 Gold with FM Radio
+	  - Typhoon Radio card (some models)
+	  - Hama Radio card
 
 	  In order to control your radio card, you will need to use programs
 	  that are compatible with the Video For Linux API.  Information on
@@ -126,14 +131,25 @@ config RADIO_GEMTEK
 	  module will be called radio-gemtek.
 
 config RADIO_GEMTEK_PORT
-	hex "GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)"
+	hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)"
 	depends on RADIO_GEMTEK=y
 	default "34c"
 	help
 	  Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
 	  0x34c, if you haven't changed the jumper setting on the card. On
 	  Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
-	  port is 0x28c.
+	  port is 0x20c, 0x248 or 0x28c.
+	  If automatic I/O port probing is enabled this port will be used only
+	  in case of automatic probing failure, ie. as a fallback.
+
+config RADIO_GEMTEK_PROBE
+	bool "Automatic I/O port probing"
+	depends on RADIO_GEMTEK=y
+	default y
+	help
+	  Say Y here to enable automatic probing for GemTek Radio card. The
+	  following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and
+	  0x28c.
 
 config RADIO_GEMTEK_PCI
 	tristate "GemTek PCI Radio Card support"

+ 429 - 189
drivers/media/radio/radio-gemtek.c

@@ -26,143 +26,383 @@
 #include <media/v4l2-common.h>
 #include <linux/spinlock.h>
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+#include <linux/version.h>	/* for KERNEL_VERSION MACRO	*/
+#define RADIO_VERSION KERNEL_VERSION(0,0,3)
+#define RADIO_BANNER "GemTek Radio card driver: v0.0.3"
 
-static struct v4l2_queryctrl radio_qctrl[] = {
-	{
-		.id            = V4L2_CID_AUDIO_MUTE,
-		.name          = "Mute",
-		.minimum       = 0,
-		.maximum       = 1,
-		.default_value = 1,
-		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-	},{
-		.id            = V4L2_CID_AUDIO_VOLUME,
-		.name          = "Volume",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535,
-		.default_value = 0xff,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-	}
-};
+/*
+ * Module info.
+ */
+
+MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
+MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
+MODULE_LICENSE("GPL");
+
+/*
+ * Module params.
+ */
 
 #ifndef CONFIG_RADIO_GEMTEK_PORT
 #define CONFIG_RADIO_GEMTEK_PORT -1
 #endif
+#ifndef CONFIG_RADIO_GEMTEK_PROBE
+#define CONFIG_RADIO_GEMTEK_PROBE 1
+#endif
 
-static int io = CONFIG_RADIO_GEMTEK_PORT;
-static int radio_nr = -1;
-static spinlock_t lock;
+static int io		= CONFIG_RADIO_GEMTEK_PORT;
+static int probe	= CONFIG_RADIO_GEMTEK_PROBE;
+static int hardmute;
+static int shutdown	= 1;
+static int keepmuted	= 1;
+static int initmute	= 1;
+static int radio_nr	= -1;
 
-struct gemtek_device
-{
-	int port;
-	unsigned long curfreq;
+module_param(io, int, 0444);
+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).");
+
+module_param(probe, bool, 0444);
+MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
+	"common I/O ports used by the card are probed.");
+
+module_param(hardmute, bool, 0644);
+MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may "
+	 "reduce static noise.");
+
+module_param(shutdown, bool, 0644);
+MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when "
+	 "module is unloaded.");
+
+module_param(keepmuted, bool, 0644);
+MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed.");
+
+module_param(initmute, bool, 0444);
+MODULE_PARM_DESC(initmute, "Mute card when module is loaded.");
+
+module_param(radio_nr, int, 0444);
+
+/*
+ * Functions for controlling the card.
+ */
+#define GEMTEK_LOWFREQ	(87*16000)
+#define GEMTEK_HIGHFREQ	(108*16000)
+
+/*
+ * Frequency calculation constants.  Intermediate frequency 10.52 MHz (nominal
+ * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz).
+ */
+#define FSCALE		8
+#define IF_OFFSET	((unsigned int)(10.52 * 16000 * (1<<FSCALE)))
+#define REF_FREQ	((unsigned int)(6.39 * 16 * (1<<FSCALE)))
+
+#define GEMTEK_CK		0x01	/* Clock signal			*/
+#define GEMTEK_DA		0x02	/* Serial data			*/
+#define GEMTEK_CE		0x04	/* Chip enable			*/
+#define GEMTEK_NS		0x08	/* No signal			*/
+#define GEMTEK_MT		0x10	/* Line mute			*/
+#define GEMTEK_STDF_3_125_KHZ	0x01	/* Standard frequency 3.125 kHz	*/
+#define GEMTEK_PLL_OFF		0x07	/* PLL off			*/
+
+#define BU2614_BUS_SIZE	32	/* BU2614 / BU2614FS bus size		*/
+
+#define SHORT_DELAY 5		/* usec */
+#define LONG_DELAY 75		/* usec */
+
+struct gemtek_device {
+	unsigned long lastfreq;
 	int muted;
+	u32 bu2614data;
 };
 
+#define BU2614_FREQ_BITS 	16 /* D0..D15, Frequency data		*/
+#define BU2614_PORT_BITS	3 /* P0..P2, Output port control data	*/
+#define BU2614_VOID_BITS	4 /* unused 				*/
+#define BU2614_FMES_BITS	1 /* CT, Frequency measurement beginning data */
+#define BU2614_STDF_BITS	3 /* R0..R2, Standard frequency data	*/
+#define BU2614_SWIN_BITS	1 /* S, Switch between FMIN / AMIN	*/
+#define BU2614_SWAL_BITS        1 /* PS, Swallow counter division (AMIN only)*/
+#define BU2614_VOID2_BITS	1 /* unused				*/
+#define BU2614_FMUN_BITS	1 /* GT, Frequency measurement time & unlock */
+#define BU2614_TEST_BITS	1 /* TS, Test data is input		*/
+
+#define BU2614_FREQ_SHIFT 	0
+#define BU2614_PORT_SHIFT	(BU2614_FREQ_BITS + BU2614_FREQ_SHIFT)
+#define BU2614_VOID_SHIFT	(BU2614_PORT_BITS + BU2614_PORT_SHIFT)
+#define BU2614_FMES_SHIFT	(BU2614_VOID_BITS + BU2614_VOID_SHIFT)
+#define BU2614_STDF_SHIFT	(BU2614_FMES_BITS + BU2614_FMES_SHIFT)
+#define BU2614_SWIN_SHIFT	(BU2614_STDF_BITS + BU2614_STDF_SHIFT)
+#define BU2614_SWAL_SHIFT	(BU2614_SWIN_BITS + BU2614_SWIN_SHIFT)
+#define BU2614_VOID2_SHIFT	(BU2614_SWAL_BITS + BU2614_SWAL_SHIFT)
+#define BU2614_FMUN_SHIFT	(BU2614_VOID2_BITS + BU2614_VOID2_SHIFT)
+#define BU2614_TEST_SHIFT	(BU2614_FMUN_BITS + BU2614_FMUN_SHIFT)
+
+#define MKMASK(field)	(((1<<BU2614_##field##_BITS) - 1) << \
+			BU2614_##field##_SHIFT)
+#define BU2614_PORT_MASK	MKMASK(PORT)
+#define BU2614_FREQ_MASK	MKMASK(FREQ)
+#define BU2614_VOID_MASK	MKMASK(VOID)
+#define BU2614_FMES_MASK	MKMASK(FMES)
+#define BU2614_STDF_MASK	MKMASK(STDF)
+#define BU2614_SWIN_MASK	MKMASK(SWIN)
+#define BU2614_SWAL_MASK	MKMASK(SWAL)
+#define BU2614_VOID2_MASK	MKMASK(VOID2)
+#define BU2614_FMUN_MASK	MKMASK(FMUN)
+#define BU2614_TEST_MASK	MKMASK(TEST)
 
-/* local things */
+static struct gemtek_device gemtek_unit;
 
-/* the correct way to mute the gemtek may be to write the last written
- * frequency || 0x10, but just writing 0x10 once seems to do it as well
+static spinlock_t lock;
+
+/*
+ * Set data which will be sent to BU2614FS.
  */
-static void gemtek_mute(struct gemtek_device *dev)
+#define gemtek_bu2614_set(dev, field, data) ((dev)->bu2614data = \
+	((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT))
+
+/*
+ * Transmit settings to BU2614FS over GemTek IC.
+ */
+static void gemtek_bu2614_transmit(struct gemtek_device *dev)
 {
-	if(dev->muted)
-		return;
+	int i, bit, q, mute;
+
 	spin_lock(&lock);
-	outb(0x10, io);
+
+	mute = dev->muted ? GEMTEK_MT : 0x00;
+
+	outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+	udelay(SHORT_DELAY);
+	outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+	udelay(LONG_DELAY);
+
+	for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) {
+	    bit = (q & 1) ? GEMTEK_DA : 0;
+	    outb_p(mute | GEMTEK_CE | bit, io);
+	    udelay(SHORT_DELAY);
+	    outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io);
+	    udelay(SHORT_DELAY);
+	}
+
+	outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+	udelay(SHORT_DELAY);
+	outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+	udelay(LONG_DELAY);
+
 	spin_unlock(&lock);
-	dev->muted = 1;
 }
 
-static void gemtek_unmute(struct gemtek_device *dev)
+/*
+ * Calculate divisor from FM-frequency for BU2614FS (3.125 KHz STDF expected).
+ */
+static unsigned long gemtek_convfreq(unsigned long freq)
 {
-	if(dev->muted == 0)
+	return ((freq<<FSCALE) + IF_OFFSET + REF_FREQ/2) / REF_FREQ;
+}
+
+/*
+ * Set FM-frequency.
+ */
+static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+{
+
+	if (keepmuted && hardmute && dev->muted)
 		return;
-	spin_lock(&lock);
-	outb(0x20, io);
-	spin_unlock(&lock);
+
+	if (freq < GEMTEK_LOWFREQ)
+		freq = GEMTEK_LOWFREQ;
+	else if (freq > GEMTEK_HIGHFREQ)
+		freq = GEMTEK_HIGHFREQ;
+
+	dev->lastfreq = freq;
 	dev->muted = 0;
+
+	gemtek_bu2614_set(dev, BU2614_PORT, 0);
+	gemtek_bu2614_set(dev, BU2614_FMES, 0);
+	gemtek_bu2614_set(dev, BU2614_SWIN, 0);	/* FM-mode	*/
+	gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+	gemtek_bu2614_set(dev, BU2614_FMUN, 1);	/* GT bit set	*/
+	gemtek_bu2614_set(dev, BU2614_TEST, 0);
+
+	gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
+	gemtek_bu2614_set(dev, BU2614_FREQ, gemtek_convfreq(freq));
+
+	gemtek_bu2614_transmit(dev);
 }
 
-static void zero(void)
+/*
+ * Set mute flag.
+ */
+static void gemtek_mute(struct gemtek_device *dev)
 {
-	outb_p(0x04, io);
-	udelay(5);
-	outb_p(0x05, io);
-	udelay(5);
+	int i;
+	dev->muted = 1;
+
+	if (hardmute) {
+		/* Turn off PLL, disable data output */
+		gemtek_bu2614_set(dev, BU2614_PORT, 0);
+		gemtek_bu2614_set(dev, BU2614_FMES, 0);	/* CT bit off	*/
+		gemtek_bu2614_set(dev, BU2614_SWIN, 0);	/* FM-mode	*/
+		gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+		gemtek_bu2614_set(dev, BU2614_FMUN, 0);	/* GT bit off	*/
+		gemtek_bu2614_set(dev, BU2614_TEST, 0);
+		gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF);
+		gemtek_bu2614_set(dev, BU2614_FREQ, 0);
+		gemtek_bu2614_transmit(dev);
+	} else {
+		spin_lock(&lock);
+
+		/* Read bus contents (CE, CK and DA). */
+		i = inb_p(io);
+		/* Write it back with mute flag set. */
+		outb_p((i >> 5) | GEMTEK_MT, io);
+		udelay(SHORT_DELAY);
+
+		spin_unlock(&lock);
+	}
 }
 
-static void one(void)
+/*
+ * Unset mute flag.
+ */
+static void gemtek_unmute(struct gemtek_device *dev)
 {
-	outb_p(0x06, io);
-	udelay(5);
-	outb_p(0x07, io);
-	udelay(5);
+	int i;
+	dev->muted = 0;
+
+	if (hardmute) {
+		/* Turn PLL back on. */
+		gemtek_setfreq(dev, dev->lastfreq);
+	} else {
+		spin_lock(&lock);
+
+		i = inb_p(io);
+		outb_p(i >> 5, io);
+		udelay(SHORT_DELAY);
+
+		spin_unlock(&lock);
+	}
 }
 
-static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+/*
+ * Get signal strength (= stereo status).
+ */
+static inline int gemtek_getsigstr(void)
 {
-	int i;
+	return inb_p(io) & GEMTEK_NS ? 0 : 1;
+}
 
-/*        freq = 78.25*((float)freq/16000.0 + 10.52); */
+/*
+ * Check if requested card acts like GemTek Radio card.
+ */
+static int gemtek_verify(int port)
+{
+	static int verified = -1;
+	int i, q;
 
-	freq /= 16;
-	freq += 10520;
-	freq *= 7825;
-	freq /= 100000;
+	if (verified == port)
+		return 1;
 
 	spin_lock(&lock);
 
-	/* 2 start bits */
-	outb_p(0x03, io);
-	udelay(5);
-	outb_p(0x07, io);
-	udelay(5);
+	q = inb_p(port);	/* Read bus contents before probing. */
+	/* Try to turn on CE, CK and DA respectively and check if card responds
+	   properly. */
+	for (i = 0; i < 3; ++i) {
+		outb_p(1 << i, port);
+		udelay(SHORT_DELAY);
 
-	/* 28 frequency bits (lsb first) */
-	for (i = 0; i < 14; i++)
-		if (freq & (1 << i))
-			one();
-		else
-			zero();
-	/* 36 unknown bits */
-	for (i = 0; i < 11; i++)
-		zero();
-	one();
-	for (i = 0; i < 4; i++)
-		zero();
-	one();
-	zero();
-
-	/* 2 end bits */
-	outb_p(0x03, io);
-	udelay(5);
-	outb_p(0x07, io);
-	udelay(5);
+		if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
+			spin_unlock(&lock);
+			return 0;
+		}
+	}
+	outb_p(q >> 5, port);	/* Write bus contents back. */
+	udelay(SHORT_DELAY);
 
 	spin_unlock(&lock);
+	verified = port;
 
-	return 0;
+	return 1;
 }
 
-static int gemtek_getsigstr(struct gemtek_device *dev)
+/*
+ * Automatic probing for card.
+ */
+static int gemtek_probe(void)
 {
-	spin_lock(&lock);
-	inb(io);
-	udelay(5);
-	spin_unlock(&lock);
-	if (inb(io) & 8)		/* bit set = no signal present */
-		return 0;
-	return 1;		/* signal present */
+	int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
+	int i;
+
+	if (!probe) {
+		printk(KERN_INFO "Automatic device probing disabled.\n");
+		return -1;
+	}
+
+	printk(KERN_INFO "Automatic device probing enabled.\n");
+
+	for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
+		printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]);
+
+		if (!request_region(ioports[i], 1, "gemtek-probe")) {
+			printk(KERN_WARNING "I/O port 0x%x busy!\n",
+			       ioports[i]);
+			continue;
+		}
+
+		if (gemtek_verify(ioports[i])) {
+			printk(KERN_INFO "Card found from I/O port "
+			       "0x%x!\n", ioports[i]);
+
+			release_region(ioports[i], 1);
+
+			io = ioports[i];
+			return io;
+		}
+
+		release_region(ioports[i], 1);
+	}
+
+	printk(KERN_ERR "Automatic probing failed!\n");
+
+	return -1;
 }
 
-static int vidioc_querycap(struct file *file, void  *priv,
-					struct v4l2_capability *v)
+/*
+ * Video 4 Linux stuff.
+ */
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id = V4L2_CID_AUDIO_MUTE,
+		.name = "Mute",
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 1,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+	}, {
+		.id = V4L2_CID_AUDIO_VOLUME,
+		.name = "Volume",
+		.minimum = 0,
+		.maximum = 65535,
+		.step = 65535,
+		.default_value = 0xff,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+
+static struct file_operations gemtek_fops = {
+	.owner		= THIS_MODULE,
+	.open		= video_exclusive_open,
+	.release	= video_exclusive_release,
+	.ioctl		= video_ioctl2,
+	.compat_ioctl	= v4l_compat_ioctl32,
+	.llseek		= no_llseek
+};
+
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *v)
 {
 	strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
 	strlcpy(v->card, "GemTek", sizeof(v->card));
@@ -172,28 +412,29 @@ static int vidioc_querycap(struct file *file, void  *priv,
 	return 0;
 }
 
-static int vidioc_g_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_device *rt = dev->priv;
-
 	if (v->index > 0)
 		return -EINVAL;
 
 	strcpy(v->name, "FM");
 	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = (87*16000);
-	v->rangehigh = (108*16000);
-	v->rxsubchans = V4L2_TUNER_SUB_MONO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xffff*gemtek_getsigstr(rt);
+	v->rangelow = GEMTEK_LOWFREQ;
+	v->rangehigh = GEMTEK_HIGHFREQ;
+	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+	v->signal = 0xffff * gemtek_getsigstr();
+	if (v->signal) {
+		v->audmode = V4L2_TUNER_MODE_STEREO;
+		v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+	} else {
+		v->audmode = V4L2_TUNER_MODE_MONO;
+		v->rxsubchans = V4L2_TUNER_SUB_MONO;
+	}
+
 	return 0;
 }
 
-static int vidioc_s_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
+static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 {
 	if (v->index > 0)
 		return -EINVAL;
@@ -201,38 +442,35 @@ static int vidioc_s_tuner(struct file *file, void *priv,
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
+			      struct v4l2_frequency *f)
 {
 	struct video_device *dev = video_devdata(file);
 	struct gemtek_device *rt = dev->priv;
 
-	rt->curfreq = f->frequency;
-	/* needs to be called twice in order for getsigstr to work */
-	gemtek_setfreq(rt, rt->curfreq);
-	gemtek_setfreq(rt, rt->curfreq);
+	gemtek_setfreq(rt, f->frequency);
+
 	return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
+			      struct v4l2_frequency *f)
 {
 	struct video_device *dev = video_devdata(file);
 	struct gemtek_device *rt = dev->priv;
 
 	f->type = V4L2_TUNER_RADIO;
-	f->frequency = rt->curfreq;
+	f->frequency = rt->lastfreq;
 	return 0;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
+			    struct v4l2_queryctrl *qc)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+	for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) {
 		if (qc->id && qc->id == radio_qctrl[i].id) {
-			memcpy(qc, &(radio_qctrl[i]),
-						sizeof(*qc));
+			memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
 			return 0;
 		}
 	}
@@ -240,7 +478,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 }
 
 static int vidioc_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
+			 struct v4l2_control *ctrl)
 {
 	struct video_device *dev = video_devdata(file);
 	struct gemtek_device *rt = dev->priv;
@@ -260,7 +498,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 }
 
 static int vidioc_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
+			 struct v4l2_control *ctrl)
 {
 	struct video_device *dev = video_devdata(file);
 	struct gemtek_device *rt = dev->priv;
@@ -282,8 +520,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 	return -EINVAL;
 }
 
-static int vidioc_g_audio (struct file *file, void *priv,
-					struct v4l2_audio *a)
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
 	if (a->index > 1)
 		return -EINVAL;
@@ -306,99 +543,102 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 	return 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
 	if (a->index != 0)
 		return -EINVAL;
 	return 0;
 }
 
-static struct gemtek_device gemtek_unit;
-
-static const struct file_operations gemtek_fops = {
-	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
-	.ioctl		= video_ioctl2,
-	.compat_ioctl	= v4l_compat_ioctl32,
-	.llseek         = no_llseek,
+static struct video_device gemtek_radio = {
+	.owner			= THIS_MODULE,
+	.name			= "GemTek Radio card",
+	.type			= VID_TYPE_TUNER,
+	.hardware		= VID_HARDWARE_GEMTEK,
+	.fops			= &gemtek_fops,
+	.vidioc_querycap	= vidioc_querycap,
+	.vidioc_g_tuner		= vidioc_g_tuner,
+	.vidioc_s_tuner		= vidioc_s_tuner,
+	.vidioc_g_audio		= vidioc_g_audio,
+	.vidioc_s_audio		= vidioc_s_audio,
+	.vidioc_g_input		= vidioc_g_input,
+	.vidioc_s_input		= vidioc_s_input,
+	.vidioc_g_frequency	= vidioc_g_frequency,
+	.vidioc_s_frequency	= vidioc_s_frequency,
+	.vidioc_queryctrl	= vidioc_queryctrl,
+	.vidioc_g_ctrl		= vidioc_g_ctrl,
+	.vidioc_s_ctrl		= vidioc_s_ctrl
 };
 
-static struct video_device gemtek_radio=
-{
-	.owner		= THIS_MODULE,
-	.name		= "GemTek radio",
-	.type		= VID_TYPE_TUNER,
-	.fops           = &gemtek_fops,
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
-};
+/*
+ * Initialization / cleanup related stuff.
+ */
 
+/*
+ * Initilize card.
+ */
 static int __init gemtek_init(void)
 {
-	if(io==-1)
-	{
-		printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n");
-		return -EINVAL;
-	}
+	printk(KERN_INFO RADIO_BANNER "\n");
 
-	if (!request_region(io, 4, "gemtek"))
-	{
-		printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
-		return -EBUSY;
-	}
+	spin_lock_init(&lock);
 
-	gemtek_radio.priv=&gemtek_unit;
+	gemtek_probe();
+	if (io) {
+		if (!request_region(io, 1, "gemtek")) {
+			printk(KERN_ERR "I/O port 0x%x already in use.\n", io);
+			return -EBUSY;
+		}
 
-	if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-	{
-		release_region(io, 4);
+		if (!gemtek_verify(io))
+			printk(KERN_WARNING "Card at I/O port 0x%x does not "
+			       "respond properly, check your "
+			       "configuration.\n", io);
+		else
+			printk(KERN_INFO "Using I/O port 0x%x.\n", io);
+	} else if (probe) {
+		printk(KERN_ERR "Automatic probing failed and no "
+		       "fixed I/O port defined.\n");
+		return -ENODEV;
+	} else {
+		printk(KERN_ERR "Automatic probing disabled but no fixed "
+		       "I/O port defined.");
 		return -EINVAL;
 	}
-	printk(KERN_INFO "GemTek Radio Card driver.\n");
 
-	spin_lock_init(&lock);
+	gemtek_radio.priv = &gemtek_unit;
 
-	/* this is _maybe_ unnecessary */
-	outb(0x01, io);
+	if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO,
+		radio_nr) == -1) {
+		release_region(io, 1);
+		return -EBUSY;
+	}
 
-	/* mute card - prevents noisy bootups */
-	gemtek_unit.muted = 0;
-	gemtek_mute(&gemtek_unit);
+	/* Set defaults */
+	gemtek_unit.lastfreq = GEMTEK_LOWFREQ;
+	gemtek_unit.bu2614data = 0;
+
+	if (initmute)
+		gemtek_mute(&gemtek_unit);
 
 	return 0;
 }
 
-MODULE_AUTHOR("Jonas Munsin");
-MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard)).");
-module_param(radio_nr, int, 0);
-
-static void __exit gemtek_cleanup(void)
+/*
+ * Module cleanup
+ */
+static void __exit gemtek_exit(void)
 {
+	if (shutdown) {
+		hardmute = 1;	/* Turn off PLL */
+		gemtek_mute(&gemtek_unit);
+	} else {
+		printk(KERN_INFO "Module unloaded but card not muted!\n");
+	}
+
 	video_unregister_device(&gemtek_radio);
-	release_region(io,4);
+	release_region(io, 1);
 }
 
 module_init(gemtek_init);
-module_exit(gemtek_cleanup);
-
-/*
-  Local variables:
-  compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c"
-  End:
-*/
+module_exit(gemtek_exit);

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

@@ -173,7 +173,7 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
 		i--;
 		p--;
 		temp = temp/2;
-       }
+	}
 
 	spin_lock(&lock);
 

+ 19 - 10
drivers/media/video/Kconfig

@@ -148,6 +148,15 @@ config VIDEO_WM8739
 	  To compile this driver as a module, choose M here: the
 	  module will be called wm8739.
 
+config VIDEO_VP27SMPX
+	tristate "Panasonic VP27s internal MPX"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the internal MPX of the Panasonic VP27s tuner.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vp27smpx.
+
 comment "Video decoders"
 
 config VIDEO_BT819
@@ -197,6 +206,13 @@ config VIDEO_OV7670
 	  OV7670 VGA camera.  It currently only works with the M88ALP01
 	  controller.
 
+config VIDEO_TCM825X
+	tristate "TCM825x camera sensor support"
+	depends on I2C && VIDEO_V4L2
+	---help---
+	  This is a driver for the Toshiba TCM825x VGA camera sensor.
+	  It is used for example in Nokia N800.
+
 config VIDEO_SAA7110
 	tristate "Philips SAA7110 video decoder"
 	depends on VIDEO_V4L1 && I2C
@@ -348,7 +364,7 @@ endmenu # encoder / decoder chips
 config VIDEO_VIVI
 	tristate "Virtual Video Driver"
 	depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI
-	select VIDEO_BUF
+	select VIDEOBUF_VMALLOC
 	default n
 	---help---
 	  Enables a virtual video driver. This device shows a color bar
@@ -489,15 +505,6 @@ config TUNER_3036
 	  Say Y here to include support for Philips SAB3036 compatible tuners.
 	  If in doubt, say N.
 
-config TUNER_TEA5761
-	bool "TEA 5761 radio tuner (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
-	depends on I2C
-	select VIDEO_TUNER
-	help
-	  Say Y here to include support for Philips TEA5761 radio tuner.
-	  If in doubt, say N.
-
 config VIDEO_VINO
 	tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
 	depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
@@ -661,6 +668,8 @@ config VIDEO_HEXIUM_GEMINI
 
 source "drivers/media/video/cx88/Kconfig"
 
+source "drivers/media/video/cx23885/Kconfig"
+
 source "drivers/media/video/ivtv/Kconfig"
 
 config VIDEO_M32R_AR

+ 20 - 8
drivers/media/video/Makefile

@@ -4,14 +4,12 @@
 
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
-tuner-objs	:=	tuner-core.o tuner-types.o tuner-simple.o \
-			mt20xx.o tda8290.o tea5767.o tda9887.o
-
-tuner-$(CONFIG_TUNER_TEA5761)	+= tea5761.o
+tuner-objs	:=	tuner-core.o tuner-types.o tda9887.o
 
 msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
 
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
+			   v4l2-int-device.o
 
 ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
   obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
@@ -63,7 +61,6 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
-obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
@@ -73,6 +70,7 @@ obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
 obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
 obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
 obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
@@ -82,8 +80,17 @@ obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
 obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-obj-$(CONFIG_VIDEO_BUF)   += video-buf.o
-obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.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_VIDEOBUF_GEN) += videobuf-core.o
+obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
+obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
@@ -97,6 +104,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 obj-$(CONFIG_VIDEO_OV7670) 	+= ov7670.o
 
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_SE401)         += se401.o
@@ -114,6 +123,9 @@ obj-$(CONFIG_USB_KONICAWC)      += usbvideo/
 obj-$(CONFIG_USB_VICAM)         += usbvideo/
 obj-$(CONFIG_USB_QUICKCAM_MESSENGER)	+= usbvideo/
 
+obj-$(CONFIG_VIDEO_IVTV) += ivtv/
+
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core

+ 1 - 2
drivers/media/video/arv.c

@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
@@ -442,7 +441,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
 	{
 		struct video_window *w = arg;
 		DEBUG(1, "VIDIOCGWIN:\n");
-		memset(w, 0, sizeof(w));
+		memset(w, 0, sizeof(*w));
 		w->width = ar->width;
 		w->height = ar->height;
 		return 0;

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

@@ -4,7 +4,7 @@ config VIDEO_BT848
 	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_BTCX
-	select VIDEO_BUF
+	select VIDEOBUF_DMA_SG
 	select VIDEO_IR
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM

+ 27 - 11
drivers/media/video/bt8xx/bttv-cards.c

@@ -27,7 +27,6 @@
 
 #include <linux/delay.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -2989,6 +2988,23 @@ struct tvcard bttv_tvcards[] = {
 		.no_tda9875     = 1,
 		.no_tda7432     = 1,
 	},
+	/* ---- card 0x95---------------------------------- */
+	[BTTV_BOARD_TYPHOON_TVTUNERPCI] = {
+		.name           = "Typhoon TV-Tuner PCI (50684)",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x3014f,
+		.muxsel         = { 2, 3, 1, 1 },
+		.gpiomux        = { 0x20001,0x10001, 0, 0 },
+		.gpiomute       = 10,
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL_I,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3276,15 +3292,15 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input)
 	btaor((2)<<5, ~(3<<5), BT848_IFORM);
 	gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]);
 
-       /* composite */
-       /* set chroma ADC to sleep */
-       btor(BT848_ADC_C_SLEEP, BT848_ADC);
-       /* set to composite video */
-       btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
-       btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+	/* composite */
+	/* set chroma ADC to sleep */
+	btor(BT848_ADC_C_SLEEP, BT848_ADC);
+	/* set to composite video */
+	btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+	btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
 
-       /* switch sync drive off */
-       gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
+	/* switch sync drive off */
+	gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
 }
 
 static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
@@ -3453,7 +3469,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
 			printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
 		}
 		break;
-       case BTTV_BOARD_STB2:
+	case BTTV_BOARD_STB2:
 		if (btv->cardid == 0x3060121a) {
 			/* Fix up entry for 3DFX VoodooTV 100,
 			   which is an OEM STB card variant. */
@@ -3784,7 +3800,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
 			for (i = 12; i < 21; i++)
 				serial *= 10, serial += ee[i] - '0';
 		}
-       } else {
+	} else {
 		unsigned short type;
 
 		for (i = 4*16; i < 8*16; i += 16) {

+ 18 - 13
drivers/media/video/bt8xx/bttv-driver.c

@@ -30,7 +30,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -155,13 +154,14 @@ MODULE_LICENSE("GPL");
 /* ----------------------------------------------------------------------- */
 /* sysfs                                                                   */
 
-static ssize_t show_card(struct class_device *cd, char *buf)
+static ssize_t show_card(struct device *cd,
+			 struct device_attribute *attr, char *buf)
 {
 	struct video_device *vfd = to_video_device(cd);
 	struct bttv *btv = dev_get_drvdata(vfd->dev);
 	return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
 }
-static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
+static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
 
 /* ----------------------------------------------------------------------- */
 /* dvb auto-load setup                                                     */
@@ -2583,7 +2583,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
 	if (check_btres(fh, RESOURCE_OVERLAY)) {
 		struct bttv_buffer *new;
 
-		new = videobuf_alloc(sizeof(*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);
@@ -3049,7 +3049,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
 		mutex_lock(&fh->cap.lock);
 		if (*on) {
 			fh->ov.tvnorm = btv->tvnorm;
-			new = videobuf_alloc(sizeof(*new));
+			new = videobuf_pci_alloc(sizeof(*new));
 			new->crop = btv->crop[!!fh->do_crop].rect;
 			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 		} else {
@@ -3072,6 +3072,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
 					     V4L2_MEMORY_MMAP);
 		if (retval < 0)
 			goto fh_unlock_and_return;
+
+		gbuffers = retval;
 		memset(mbuf,0,sizeof(*mbuf));
 		mbuf->frames = gbuffers;
 		mbuf->size   = gbuffers * gbufsize;
@@ -3142,9 +3144,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
 			retval = -EIO;
 			/* fall through */
 		case STATE_DONE:
-			videobuf_dma_sync(&fh->cap,&buf->vb.dma);
+		{
+			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;
@@ -3338,7 +3343,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
 			if (check_btres(fh, RESOURCE_OVERLAY)) {
 				struct bttv_buffer *new;
 
-				new = videobuf_alloc(sizeof(*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);
@@ -3697,7 +3702,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
 				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
-			fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
+			fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
 			if (NULL == fh->cap.read_buf) {
 				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
@@ -3764,13 +3769,13 @@ static int bttv_open(struct inode *inode, struct file *file)
 	fh->ov.setup_ok = 0;
 	v4l2_prio_open(&btv->prio,&fh->prio);
 
-	videobuf_queue_init(&fh->cap, &bttv_video_qops,
+	videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
 			    btv->c.pci, &btv->s_lock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct bttv_buffer),
 			    fh);
-	videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
+	videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
 			    btv->c.pci, &btv->s_lock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB,
@@ -4613,9 +4618,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
 		goto err;
 	printk(KERN_INFO "bttv%d: registered device video%d\n",
 	       btv->c.nr,btv->video_dev->minor & 0x1f);
-	if (class_device_create_file(&btv->video_dev->class_dev,
-				     &class_device_attr_card)<0) {
-		printk(KERN_ERR "bttv%d: class_device_create_file 'card' "
+	if (device_create_file(&btv->video_dev->class_dev,
+				     &dev_attr_card)<0) {
+		printk(KERN_ERR "bttv%d: device_create_file 'card' "
 		       "failed\n", btv->c.nr);
 		goto err;
 	}

+ 2 - 4
drivers/media/video/bt8xx/bttv-gpio.c

@@ -106,11 +106,9 @@ int bttv_sub_add_device(struct bttv_core *core, char *name)
 
 int bttv_sub_del_devices(struct bttv_core *core)
 {
-	struct bttv_sub_device *sub;
-	struct list_head *item,*save;
+	struct bttv_sub_device *sub, *save;
 
-	list_for_each_safe(item,save,&core->subs) {
-		sub = list_entry(item,struct bttv_sub_device,list);
+	list_for_each_entry_safe(sub, save, &core->subs, list) {
 		list_del(&sub->list);
 		device_unregister(&sub->dev);
 	}

+ 0 - 1
drivers/media/video/bt8xx/bttv-i2c.c

@@ -28,7 +28,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 

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

@@ -19,7 +19,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>

部分文件因为文件数量过多而无法显示