ソースを参照

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

* master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (244 commits)
  V4L/DVB (4210b): git-dvb: tea575x-tuner build fix
  V4L/DVB (4210a): git-dvb versus matroxfb
  V4L/DVB (4209): Added some BTTV PCI IDs for newer boards
  Fixes some sync issues between V4L/DVB development and GIT
  V4L/DVB (4206): Cx88-blackbird: always set encoder height based on tvnorm->id
  V4L/DVB (4205): Merge tda9887 module into tuner.
  V4L/DVB (4203): Explicitly set the enum values.
  V4L/DVB (4202): allow selecting CX2341x port mode
  V4L/DVB (4200): Disable bitrate_mode when encoding mpeg-1.
  V4L/DVB (4199): Add cx2341x-specific control array to cx2341x.c
  V4L/DVB (4198): Avoid newer usages of obsoleted experimental MPEGCOMP API
  V4L/DVB (4197): Port new MPEG API to saa7134-empress with saa6752hs
  V4L/DVB (4196): Port cx88-blackbird to the new MPEG API.
  V4L/DVB (4193): Update cx2341x fw encoding API doc.
  V4L/DVB (4192): Use control helpers for saa7115, cx25840, msp3400.
  V4L/DVB (4191): Add CX2341X MPEG encoder module.
  V4L/DVB (4190): Add helper functions for control processing to v4l2-common.
  V4L/DVB (4189): Add videodev support for VIDIOC_S/G/TRY_EXT_CTRLS.
  V4L/DVB (4188): Add new MPEG control/ioctl definitions to videodev2.h
  V4L/DVB (4186): Add support for the DNTV Live! mini DVB-T card.
  ...
Linus Torvalds 19 年 前
コミット
25581ad107
100 ファイル変更5141 行追加1442 行削除
  1. 2 2
      Documentation/video4linux/CARDLIST.bttv
  2. 7 2
      Documentation/video4linux/CARDLIST.cx88
  3. 1 0
      Documentation/video4linux/CARDLIST.saa7134
  4. 2 1
      Documentation/video4linux/CARDLIST.tuner
  5. 3 200
      Documentation/video4linux/CQcam.txt
  6. 23 0
      Documentation/video4linux/Zoran
  7. 4 4
      Documentation/video4linux/bttv/CONTRIBUTORS
  8. 69 0
      Documentation/video4linux/cx2341x/fw-calling.txt
  9. 319 0
      Documentation/video4linux/cx2341x/fw-decoder-api.txt
  10. 94 0
      Documentation/video4linux/cx2341x/fw-dma.txt
  11. 694 0
      Documentation/video4linux/cx2341x/fw-encoder-api.txt
  12. 141 0
      Documentation/video4linux/cx2341x/fw-memory.txt
  13. 342 0
      Documentation/video4linux/cx2341x/fw-osd-api.txt
  14. 49 0
      Documentation/video4linux/cx2341x/fw-upload.txt
  15. 54 0
      Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
  16. 26 26
      Documentation/video4linux/et61x251.txt
  17. 84 84
      Documentation/video4linux/ibmcam.txt
  18. 16 16
      Documentation/video4linux/ov511.txt
  19. 39 39
      Documentation/video4linux/sn9c102.txt
  20. 192 0
      Documentation/video4linux/v4lgrab.c
  21. 81 81
      Documentation/video4linux/w9968cf.txt
  22. 48 32
      Documentation/video4linux/zc0301.txt
  23. 5 2
      drivers/media/Kconfig
  24. 1 1
      drivers/media/common/Makefile
  25. 0 1
      drivers/media/common/ir-functions.c
  26. 71 11
      drivers/media/common/ir-keymaps.c
  27. 4 0
      drivers/media/common/saa7146_fops.c
  28. 1 0
      drivers/media/common/saa7146_hlp.c
  29. 2 0
      drivers/media/common/saa7146_video.c
  30. 0 12
      drivers/media/common/saa7146_vv_ksyms.c
  31. 73 49
      drivers/media/dvb/b2c2/flexcop-fe-tuner.c
  32. 7 12
      drivers/media/dvb/b2c2/flexcop-pci.c
  33. 4 6
      drivers/media/dvb/b2c2/flexcop-usb.c
  34. 4 8
      drivers/media/dvb/b2c2/flexcop.c
  35. 8 3
      drivers/media/dvb/bt8xx/bt878.c
  36. 477 129
      drivers/media/dvb/bt8xx/dst.c
  37. 101 15
      drivers/media/dvb/bt8xx/dst_ca.c
  38. 29 4
      drivers/media/dvb/bt8xx/dst_common.h
  39. 61 57
      drivers/media/dvb/bt8xx/dvb-bt8xx.c
  40. 2 0
      drivers/media/dvb/bt8xx/dvb-bt8xx.h
  41. 1 1
      drivers/media/dvb/cinergyT2/Kconfig
  42. 6 2
      drivers/media/dvb/cinergyT2/cinergyT2.c
  43. 3 3
      drivers/media/dvb/dvb-core/Makefile
  44. 0 3
      drivers/media/dvb/dvb-core/dmxdev.c
  45. 23 2
      drivers/media/dvb/dvb-core/dvb_ca_en50221.c
  46. 2 2
      drivers/media/dvb/dvb-core/dvb_demux.c
  47. 85 66
      drivers/media/dvb/dvb-core/dvb_frontend.c
  48. 44 1
      drivers/media/dvb/dvb-core/dvb_frontend.h
  49. 145 0
      drivers/media/dvb/dvb-core/dvb_math.c
  50. 58 0
      drivers/media/dvb/dvb-core/dvb_math.h
  51. 154 76
      drivers/media/dvb/dvb-core/dvb_net.c
  52. 3 2
      drivers/media/dvb/dvb-core/dvbdev.c
  53. 3 1
      drivers/media/dvb/dvb-core/dvbdev.h
  54. 10 0
      drivers/media/dvb/dvb-usb/Kconfig
  55. 3 0
      drivers/media/dvb/dvb-usb/Makefile
  56. 29 19
      drivers/media/dvb/dvb-usb/cxusb.c
  57. 6 3
      drivers/media/dvb/dvb-usb/dibusb-common.c
  58. 4 3
      drivers/media/dvb/dvb-usb/dibusb-mb.c
  59. 9 6
      drivers/media/dvb/dvb-usb/digitv.c
  60. 2 6
      drivers/media/dvb/dvb-usb/dtt200u-fe.c
  61. 8 9
      drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
  62. 15 9
      drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
  63. 3 1
      drivers/media/dvb/dvb-usb/dvb-usb-ids.h
  64. 3 3
      drivers/media/dvb/dvb-usb/dvb-usb.h
  65. 272 0
      drivers/media/dvb/dvb-usb/gp8psk-fe.c
  66. 256 0
      drivers/media/dvb/dvb-usb/gp8psk.c
  67. 79 0
      drivers/media/dvb/dvb-usb/gp8psk.h
  68. 1 1
      drivers/media/dvb/dvb-usb/umt-010.c
  69. 3 4
      drivers/media/dvb/dvb-usb/vp702x-fe.c
  70. 2 7
      drivers/media/dvb/dvb-usb/vp7045-fe.c
  71. 17 1
      drivers/media/dvb/frontends/Kconfig
  72. 2 0
      drivers/media/dvb/frontends/Makefile
  73. 1 3
      drivers/media/dvb/frontends/bcm3510.c
  74. 4 2
      drivers/media/dvb/frontends/bsbe1.h
  75. 4 2
      drivers/media/dvb/frontends/bsru6.h
  76. 18 13
      drivers/media/dvb/frontends/cx22700.c
  77. 0 4
      drivers/media/dvb/frontends/cx22700.h
  78. 5 24
      drivers/media/dvb/frontends/cx22702.c
  79. 0 7
      drivers/media/dvb/frontends/cx22702.h
  80. 8 18
      drivers/media/dvb/frontends/cx24110.c
  81. 0 5
      drivers/media/dvb/frontends/cx24110.h
  82. 51 144
      drivers/media/dvb/frontends/cx24123.c
  83. 0 13
      drivers/media/dvb/frontends/cx24123.h
  84. 0 2
      drivers/media/dvb/frontends/dib3000-common.h
  85. 0 4
      drivers/media/dvb/frontends/dib3000.h
  86. 4 7
      drivers/media/dvb/frontends/dib3000mb.c
  87. 5 9
      drivers/media/dvb/frontends/dib3000mc.c
  88. 176 5
      drivers/media/dvb/frontends/dvb-pll.c
  89. 16 2
      drivers/media/dvb/frontends/dvb-pll.h
  90. 8 13
      drivers/media/dvb/frontends/dvb_dummy_fe.c
  91. 149 0
      drivers/media/dvb/frontends/isl6421.c
  92. 46 0
      drivers/media/dvb/frontends/isl6421.h
  93. 5 6
      drivers/media/dvb/frontends/l64781.c
  94. 0 4
      drivers/media/dvb/frontends/l64781.h
  95. 64 0
      drivers/media/dvb/frontends/lg_h06xf.h
  96. 11 8
      drivers/media/dvb/frontends/lgdt330x.c
  97. 0 1
      drivers/media/dvb/frontends/lgdt330x.h
  98. 145 0
      drivers/media/dvb/frontends/lnbp21.c
  99. 4 98
      drivers/media/dvb/frontends/lnbp21.h
  100. 26 20
      drivers/media/dvb/frontends/mt312.c

+ 2 - 2
Documentation/video4linux/CARDLIST.bttv

@@ -87,7 +87,7 @@
  86 -> Osprey 101/151 w/ svid
  87 -> Osprey 200/201/250/251
  88 -> Osprey 200/250                                      [0070:ff01]
- 89 -> Osprey 210/220
+ 89 -> Osprey 210/220/230
  90 -> Osprey 500                                          [0070:ff02]
  91 -> Osprey 540                                          [0070:ff04]
  92 -> Osprey 2000                                         [0070:ff03]
@@ -111,7 +111,7 @@
 110 -> IVC-100                                             [ff00:a132]
 111 -> IVC-120G                                            [ff00:a182,ff01:a182,ff02:a182,ff03:a182,ff04:a182,ff05:a182,ff06:a182,ff07:a182,ff08:a182,ff09:a182,ff0a:a182,ff0b:a182,ff0c:a182,ff0d:a182,ff0e:a182,ff0f:a182]
 112 -> pcHDTV HD-2000 TV                                   [7063:2000]
-113 -> Twinhan DST + clones                                [11bd:0026,1822:0001,270f:fc00]
+113 -> Twinhan DST + clones                                [11bd:0026,1822:0001,270f:fc00,1822:0026]
 114 -> Winfast VC100                                       [107d:6607]
 115 -> Teppro TEV-560/InterVision IV-560
 116 -> SIMUS GVC1100                                       [aa6a:82b2]

+ 7 - 2
Documentation/video4linux/CARDLIST.cx88

@@ -15,7 +15,7 @@
  14 -> KWorld/VStream XPert DVB-T                          [17de:08a6]
  15 -> DViCO FusionHDTV DVB-T1                             [18ac:db00]
  16 -> KWorld LTV883RF
- 17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810]
+ 17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810,18ac:d800]
  18 -> Hauppauge Nova-T DVB-T                              [0070:9002,0070:9001]
  19 -> Conexant DVB-T reference design                     [14f1:0187]
  20 -> Provideo PV259                                      [1540:2580]
@@ -40,8 +40,13 @@
  39 -> KWorld DVB-S 100                                    [17de:08b2]
  40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid                [0070:9400,0070:9402]
  41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)  [0070:9800,0070:9802]
- 42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025]
+ 42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025,1822:0019]
  43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1]
  44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50,18ac:db54]
  45 -> KWorld HardwareMpegTV XPert                         [17de:0840]
  46 -> DViCO FusionHDTV DVB-T Hybrid                       [18ac:db40,18ac:db44]
+ 47 -> pcHDTV HD5500 HDTV                                  [7063:5500]
+ 48 -> Kworld MCE 200 Deluxe                               [17de:0841]
+ 49 -> PixelView PlayTV P7000                              [1554:4813]
+ 50 -> NPG Tech Real TV FM Top 10                          [14f1:0842]
+ 51 -> WinFast DTV2000 H                                   [107d:665e]

+ 1 - 0
Documentation/video4linux/CARDLIST.saa7134

@@ -93,3 +93,4 @@
  92 -> AVerMedia A169 B1                        [1461:6360]
  93 -> Medion 7134 Bridge #2                    [16be:0005]
  94 -> LifeView FlyDVB-T Hybrid Cardbus         [5168:3306,5168:3502]
+ 95 -> LifeView FlyVIDEO3000 (NTSC)             [5169:0138]

+ 2 - 1
Documentation/video4linux/CARDLIST.tuner

@@ -62,7 +62,7 @@ tuner=60 - Thomson DTT 761X (ATSC/NTSC)
 tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
 tuner=62 - Philips TEA5767HN FM Radio
 tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
-tuner=64 - LG TDVS-H062F/TUA6034
+tuner=64 - LG TDVS-H06xF
 tuner=65 - Ymec TVF66T5-B/DFF
 tuner=66 - LG TALN series
 tuner=67 - Philips TD1316 Hybrid Tuner
@@ -71,3 +71,4 @@ tuner=69 - Tena TNF 5335 and similar models
 tuner=70 - Samsung TCPN 2121P30A
 tuner=71 - Xceive xc3028
 tuner=72 - Thomson FE6600
+tuner=73 - Samsung TCPG 6121P30A

+ 3 - 200
Documentation/video4linux/CQcam.txt

@@ -185,207 +185,10 @@ this work is documented at the video4linux2 site listed below.
 
 9.0 --- A sample program using v4lgrabber,
 
-This program is a simple image grabber that will copy a frame from the
+v4lgrab is a simple image grabber that will copy a frame from the
 first video device, /dev/video0 to standard output in portable pixmap
-format (.ppm)  Using this like: 'v4lgrab | convert - c-qcam.jpg'
-produced this picture of me at
-    http://mug.sys.virginia.edu/~drf5n/extras/c-qcam.jpg
-
--------------------- 8< ---------------- 8< -----------------------------
-
-/* Simple Video4Linux image grabber. */
-/*
- *	Video4Linux Driver Test/Example Framegrabbing Program
- *
- *	Compile with:
- *		gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
- *      Use as:
- *              v4lgrab >image.ppm
- *
- *	Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>
- *      Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c
- *      with minor modifications (Dave Forrest, drf5n@virginia.edu).
- *
- */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-
-#include <linux/types.h>
-#include <linux/videodev.h>
-
-#define FILE "/dev/video0"
-
-/* Stole this from tvset.c */
-
-#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b)                   \
-{                                                                       \
-	switch (format)                                                 \
-	{                                                               \
-		case VIDEO_PALETTE_GREY:                                \
-			switch (depth)                                  \
-			{                                               \
-				case 4:                                 \
-				case 6:                                 \
-				case 8:                                 \
-					(r) = (g) = (b) = (*buf++ << 8);\
-					break;                          \
-									\
-				case 16:                                \
-					(r) = (g) = (b) =               \
-						*((unsigned short *) buf);      \
-					buf += 2;                       \
-					break;                          \
-			}                                               \
-			break;                                          \
-									\
-									\
-		case VIDEO_PALETTE_RGB565:                              \
-		{                                                       \
-			unsigned short tmp = *(unsigned short *)buf;    \
-			(r) = tmp&0xF800;                               \
-			(g) = (tmp<<5)&0xFC00;                          \
-			(b) = (tmp<<11)&0xF800;                         \
-			buf += 2;                                       \
-		}                                                       \
-		break;                                                  \
-									\
-		case VIDEO_PALETTE_RGB555:                              \
-			(r) = (buf[0]&0xF8)<<8;                         \
-			(g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8;    \
-			(b) = ((buf[1] << 2 ) & 0xF8)<<8;               \
-			buf += 2;                                       \
-			break;                                          \
-									\
-		case VIDEO_PALETTE_RGB24:                               \
-			(r) = buf[0] << 8; (g) = buf[1] << 8;           \
-			(b) = buf[2] << 8;                              \
-			buf += 3;                                       \
-			break;                                          \
-									\
-		default:                                                \
-			fprintf(stderr,                                 \
-				"Format %d not yet supported\n",        \
-				format);                                \
-	}                                                               \
-}
-
-int get_brightness_adj(unsigned char *image, long size, int *brightness) {
-  long i, tot = 0;
-  for (i=0;i<size*3;i++)
-    tot += image[i];
-  *brightness = (128 - tot/(size*3))/3;
-  return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
-}
-
-int main(int argc, char ** argv)
-{
-  int fd = open(FILE, O_RDONLY), f;
-  struct video_capability cap;
-  struct video_window win;
-  struct video_picture vpic;
-
-  unsigned char *buffer, *src;
-  int bpp = 24, r, g, b;
-  unsigned int i, src_depth;
-
-  if (fd < 0) {
-    perror(FILE);
-    exit(1);
-  }
-
-  if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
-    perror("VIDIOGCAP");
-    fprintf(stderr, "(" FILE " not a video4linux device?)\n");
-    close(fd);
-    exit(1);
-  }
-
-  if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
-    perror("VIDIOCGWIN");
-    close(fd);
-    exit(1);
-  }
-
-  if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
-    perror("VIDIOCGPICT");
-    close(fd);
-    exit(1);
-  }
-
-  if (cap.type & VID_TYPE_MONOCHROME) {
-    vpic.depth=8;
-    vpic.palette=VIDEO_PALETTE_GREY;    /* 8bit grey */
-    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-      vpic.depth=6;
-      if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-	vpic.depth=4;
-	if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-	  fprintf(stderr, "Unable to find a supported capture format.\n");
-	  close(fd);
-	  exit(1);
-	}
-      }
-    }
-  } else {
-    vpic.depth=24;
-    vpic.palette=VIDEO_PALETTE_RGB24;
-
-    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-      vpic.palette=VIDEO_PALETTE_RGB565;
-      vpic.depth=16;
-
-      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-	vpic.palette=VIDEO_PALETTE_RGB555;
-	vpic.depth=15;
-
-	if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-	  fprintf(stderr, "Unable to find a supported capture format.\n");
-	  return -1;
-	}
-      }
-    }
-  }
-
-  buffer = malloc(win.width * win.height * bpp);
-  if (!buffer) {
-    fprintf(stderr, "Out of memory.\n");
-    exit(1);
-  }
-
-  do {
-    int newbright;
-    read(fd, buffer, win.width * win.height * bpp);
-    f = get_brightness_adj(buffer, win.width * win.height, &newbright);
-    if (f) {
-      vpic.brightness += (newbright << 8);
-      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-	perror("VIDIOSPICT");
-	break;
-      }
-    }
-  } while (f);
-
-  fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
-
-  src = buffer;
-
-  for (i = 0; i < win.width * win.height; i++) {
-    READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
-    fputc(r>>8, stdout);
-    fputc(g>>8, stdout);
-    fputc(b>>8, stdout);
-  }
-
-  close(fd);
-  return 0;
-}
--------------------- 8< ---------------- 8< -----------------------------
+format (.ppm)  To produce .jpg output, you can use it like this:
+'v4lgrab | convert - c-qcam.jpg'
 
 
 10.0 --- Other Information

+ 23 - 0
Documentation/video4linux/Zoran

@@ -33,6 +33,21 @@ Inputs/outputs: Composite and S-video
 Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
 Card number: 7
 
+AverMedia 6 Eyes AVS6EYES:
+* Zoran zr36067 PCI controller
+* Zoran zr36060 MJPEG codec
+* Samsung ks0127 TV decoder
+* Conexant bt866  TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+		videocodec, ks0127, bt866, zr36060, zr36067
+Inputs/outputs: Six physical inputs. 1-6 are composite,
+		1-2, 3-4, 5-6 doubles as S-video,
+		1-3 triples as component.
+		One composite output.
+Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
+Card number: 8
+Not autodetected, card=8 is necessary.
+
 Linux Media Labs LML33:
 * Zoran zr36067 PCI controller
 * Zoran zr36060 MJPEG codec
@@ -192,6 +207,10 @@ Micronas vpx3220a TV decoder
 was introduced in 1996, is used in the DC30 and DC30+ and
 can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC 44, PAL 60, SECAM,NTSC Comb
 
+Samsung ks0127 TV decoder
+is used in the AVS6EYES card and
+can handle: NTSC-M/N/44, PAL-M/N/B/G/H/I/D/K/L and SECAM
+
 ===========================
 
 1.2 What the TV encoder can do an what not
@@ -221,6 +240,10 @@ ITT mse3000 TV encoder
 was introduced in 1991, is used in the DC10 old
 can generate: PAL , NTSC , SECAM
 
+Conexant bt866 TV encoder
+is used in AVS6EYES, and
+can generate: NTSC/PAL, PAL­M, PAL­N
+
 The adv717x, should be able to produce PAL N. But you find nothing PAL N
 specific in the registers. Seem that you have to reuse a other standard
 to generate PAL N, maybe it would work if you use the PAL M settings.

+ 4 - 4
Documentation/video4linux/bttv/CONTRIBUTORS

@@ -1,4 +1,4 @@
-Contributors to bttv: 
+Contributors to bttv:
 
 Michael Chu <mmchu@pobox.com>
   AverMedia fix and more flexible card recognition
@@ -8,8 +8,8 @@ Alan Cox <alan@redhat.com>
 
 Chris Kleitsch
   Hardware I2C
-  
-Gerd Knorr <kraxel@cs.tu-berlin.de> 
+
+Gerd Knorr <kraxel@cs.tu-berlin.de>
   Radio card (ITT sound processor)
 
 bigfoot <bigfoot@net-way.net>
@@ -18,7 +18,7 @@ Ragnar Hojland Espinosa <ragnar@macula.net>
 
 
 + many more (please mail me if you are missing in this list and would
-             like to be mentioned)
+	     like to be mentioned)
 
 
 

+ 69 - 0
Documentation/video4linux/cx2341x/fw-calling.txt

@@ -0,0 +1,69 @@
+This page describes how to make calls to the firmware api.
+
+How to call
+===========
+
+The preferred calling convention is known as the firmware mailbox. The
+mailboxes are basically a fixed length array that serves as the call-stack.
+
+Firmware mailboxes can be located by searching the encoder and decoder memory
+for a 16 byte signature. That signature will be located on a 256-byte boundary.
+
+Signature:
+0x78, 0x56, 0x34, 0x12, 0x12, 0x78, 0x56, 0x34,
+0x34, 0x12, 0x78, 0x56, 0x56, 0x34, 0x12, 0x78
+
+The firmware implements 20 mailboxes of 20 32-bit words. The first 10 are
+reserved for API calls. The second 10 are used by the firmware for event
+notification.
+
+  Index  Name
+  -----  ----
+  0      Flags
+  1      Command
+  2      Return value
+  3      Timeout
+  4-19   Parameter/Result
+
+
+The flags are defined in the following table. The direction is from the
+perspective of the firmware.
+
+  Bit  Direction  Purpose
+  ---  ---------  -------
+  2    O          Firmware has processed the command.
+  1    I          Driver has finished setting the parameters.
+  0    I          Driver is using this mailbox.
+
+
+The command is a 32-bit enumerator. The API specifics may be found in the
+fw-*-api.txt documents.
+
+The return value is a 32-bit enumerator. Only two values are currently defined:
+0=success and -1=command undefined.
+
+There are 16 parameters/results 32-bit fields. The driver populates these fields
+with values for all the parameters required by the call. The driver overwrites
+these fields with result values returned by the call. The API specifics may be
+found in the fw-*-api.txt documents.
+
+The timeout value protects the card from a hung driver thread. If the driver
+doesn't handle the completed call within the timeout specified, the firmware
+will reset that mailbox.
+
+To make an API call, the driver iterates over each mailbox looking for the
+first one available (bit 0 has been cleared). The driver sets that bit, fills
+in the command enumerator, the timeout value and any required parameters. The
+driver then sets the parameter ready bit (bit 1). The firmware scans the
+mailboxes for pending commands, processes them, sets the result code, populates
+the result value array with that call's return values and sets the call
+complete bit (bit 2). Once bit 2 is set, the driver should retrieve the results
+and clear all the flags. If the driver does not perform this task within the
+time set in the timeout register, the firmware will reset that mailbox.
+
+Event notifications are sent from the firmware to the host. The host tells the
+firmware which events it is interested in via an API call. That call tells the
+firmware which notification mailbox to use. The firmware signals the host via
+an interrupt. Only the 16 Results fields are used, the Flags, Command, Return
+value and Timeout words are not used.
+

+ 319 - 0
Documentation/video4linux/cx2341x/fw-decoder-api.txt

@@ -0,0 +1,319 @@
+Decoder firmware API description
+================================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_PING_FW
+Enum 	0/0x00
+Description
+	This API call does nothing. It may be used to check if the firmware
+	is responding.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_START_PLAYBACK
+Enum 	1/0x01
+Description
+	Begin or resume playback.
+Param[0]
+	0 based frame number in GOP to begin playback from.
+Param[1]
+	Specifies the number of muted audio frames to play before normal
+	audio resumes.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_STOP_PLAYBACK
+Enum 	2/0x02
+Description
+	Ends playback and clears all decoder buffers. If PTS is not zero,
+	playback stops at specified PTS.
+Param[0]
+	Display 0=last frame, 1=black
+Param[1]
+	PTS low
+Param[2]
+	PTS high
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_PLAYBACK_SPEED
+Enum 	3/0x03
+Description
+	Playback stream at speed other than normal. There are two modes of
+	operation:
+	    Smooth: host transfers entire stream and firmware drops unused
+		    frames.
+	    Coarse: host drops frames based on indexing as required to achieve
+		    desired speed.
+Param[0]
+	Bitmap:
+	    0:7  0 normal
+		 1 fast only "1.5 times"
+		 n nX fast, 1/nX slow
+	    30   Framedrop:
+		     '0' during 1.5 times play, every other B frame is dropped
+		     '1' during 1.5 times play, stream is unchanged (bitrate
+			 must not exceed 8mbps)
+	    31   Speed:
+		     '0' slow
+		     '1' fast
+Param[1]
+	Direction: 0=forward, 1=reverse
+Param[2]
+	Picture mask:
+	    1=I frames
+	    3=I, P frames
+	    7=I, P, B frames
+Param[3]
+	B frames per GOP (for reverse play only)
+Param[4]
+	Mute audio: 0=disable, 1=enable
+Param[5]
+	Display 0=frame, 1=field
+Param[6]
+	Specifies the number of muted audio frames to play before normal audio
+	resumes.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_STEP_VIDEO
+Enum 	5/0x05
+Description
+	Each call to this API steps the playback to the next unit defined below
+	in the current playback direction.
+Param[0]
+	0=frame, 1=top field, 2=bottom field
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_DMA_BLOCK_SIZE
+Enum 	8/0x08
+Description
+	Set DMA transfer block size. Counterpart to API 0xC9
+Param[0]
+	DMA transfer block size in bytes. A different size may be specified
+	when issuing the DMA transfer command.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_GET_XFER_INFO
+Enum 	9/0x09
+Description
+	This API call may be used to detect an end of stream condtion.
+Result[0]
+	Stream type
+Result[1]
+	Address offset
+Result[2]
+	Maximum bytes to transfer
+Result[3]
+	Buffer fullness
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_GET_DMA_STATUS
+Enum 	10/0x0A
+Description
+	Status of the last DMA transfer
+Result[0]
+	Bit 1 set means transfer complete
+	Bit 2 set means DMA error
+	Bit 3 set means linked list error
+Result[1]
+	DMA type: 0=MPEG, 1=OSD, 2=YUV
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SCHED_DMA_FROM_HOST
+Enum 	11/0x0B
+Description
+	Setup DMA from host operation. Counterpart to API 0xCC
+Param[0]
+	Memory address of link list
+Param[1]
+	Total # of bytes to transfer
+Param[2]
+	DMA type (0=MPEG, 1=OSD, 2=YUV)
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_PAUSE_PLAYBACK
+Enum 	13/0x0D
+Description
+	Freeze playback immediately. In this mode, when internal buffers are
+	full, no more data will be accepted and data request IRQs will be
+	masked.
+Param[0]
+	Display: 0=last frame, 1=black
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_HALT_FW
+Enum 	14/0x0E
+Description
+	The firmware is halted and no further API calls are serviced until
+	the firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_STANDARD
+Enum 	16/0x10
+Description
+	Selects display standard
+Param[0]
+	0=NTSC, 1=PAL
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_GET_VERSION
+Enum 	17/0x11
+Description
+	Returns decoder firmware version information
+Result[0]
+	Version bitmask:
+	    Bits  0:15 build
+	    Bits 16:23 minor
+	    Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_STREAM_INPUT
+Enum 	20/0x14
+Description
+	Select decoder stream input port
+Param[0]
+	0=memory (default), 1=streaming
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_GET_TIMING_INFO
+Enum 	21/0x15
+Description
+	Returns timing information from start of playback
+Result[0]
+	Frame count by decode order
+Result[1]
+	Video PTS bits 0:31 by display order
+Result[2]
+	Video PTS bit 32 by display order
+Result[3]
+	SCR bits 0:31 by display order
+Result[4]
+	SCR bit 32 by display order
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_AUDIO_MODE
+Enum 	22/0x16
+Description
+	Select audio mode
+Param[0]
+	Dual mono mode action
+Param[1]
+	Stereo mode action:
+	    0=Stereo, 1=Left, 2=Right, 3=Mono, 4=Swap, -1=Unchanged
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_EVENT_NOTIFICATION
+Enum 	23/0x17
+Description
+	Setup firmware to notify the host about a particular event.
+	Counterpart to API 0xD5
+Param[0]
+	Event: 0=Audio mode change between stereo and dual channel
+Param[1]
+	Notification 0=disabled, 1=enabled
+Param[2]
+	Interrupt bit
+Param[3]
+	Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_DISPLAY_BUFFERS
+Enum 	24/0x18
+Description
+	Number of display buffers. To decode all frames in reverse playback you
+	must use nine buffers.
+Param[0]
+	0=six buffers, 1=nine buffers
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_EXTRACT_VBI
+Enum 	25/0x19
+Description
+	Extracts VBI data
+Param[0]
+	0=extract from extension & user data, 1=extract from private packets
+Result[0]
+	VBI table location
+Result[1]
+	VBI table size
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_DECODER_SOURCE
+Enum 	26/0x1A
+Description
+	Selects decoder source. Ensure that the parameters passed to this
+	API match the encoder settings.
+Param[0]
+	Mode: 0=MPEG from host, 1=YUV from encoder, 2=YUV from host
+Param[1]
+	YUV picture width
+Param[2]
+	YUV picture height
+Param[3]
+	Bitmap: see Param[0] of API 0xBD
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_AUDIO_OUTPUT
+Enum 	27/0x1B
+Description
+	Select audio output format
+Param[0]
+	Bitmask:
+	     0:1  Data size:
+		      '00' 16 bit
+		      '01' 20 bit
+		      '10' 24 bit
+	     2:7  Unused
+	     8:9  Mode:
+		      '00' 2 channels
+		      '01' 4 channels
+		      '10' 6 channels
+		      '11' 6 channels with one line data mode
+			   (for left justified MSB first mode, 20 bit only)
+	    10:11 Unused
+	    12:13 Channel format:
+		      '00' right justified MSB first mode
+		      '01' left justified MSB first mode
+		      '10' I2S mode
+	    14:15 Unused
+	    16:21 Right justify bit count
+	    22:31 Unused
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_AV_DELAY
+Enum 	28/0x1C
+Description
+	Set audio/video delay in 90Khz ticks
+Param[0]
+	0=A/V in sync, negative=audio lags, positive=video lags
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_PREBUFFERING
+Enum 	30/0x1E
+Description
+	Decoder prebuffering, when enabled up to 128KB are buffered for
+	streams <8mpbs or 640KB for streams >8mbps
+Param[0]
+	0=off, 1=on

+ 94 - 0
Documentation/video4linux/cx2341x/fw-dma.txt

@@ -0,0 +1,94 @@
+This page describes the structures and procedures used by the cx2341x DMA
+engine.
+
+Introduction
+============
+
+The cx2341x PCI interface is busmaster capable. This means it has a DMA
+engine to efficiently transfer large volumes of data between the card and main
+memory without requiring help from a CPU. Like most hardware, it must operate
+on contiguous physical memory. This is difficult to come by in large quantities
+on virtual memory machines.
+
+Therefore, it also supports a technique called "scatter-gather". The card can
+transfer multiple buffers in one operation. Instead of allocating one large
+contiguous buffer, the driver can allocate several smaller buffers.
+
+In practice, I've seen the average transfer to be roughly 80K, but transfers
+above 128K were not uncommon, particularly at startup. The 128K figure is
+important, because that is the largest block that the kernel can normally
+allocate. Even still, 128K blocks are hard to come by, so the driver writer is
+urged to choose a smaller block size and learn the scatter-gather technique.
+
+Mailbox #10 is reserved for DMA transfer information.
+
+Flow
+====
+
+This section describes, in general, the order of events when handling DMA
+transfers. Detailed information follows this section.
+
+- The card raises the Encoder interrupt.
+- The driver reads the transfer type, offset and size from Mailbox #10.
+- The driver constructs the scatter-gather array from enough free dma buffers
+  to cover the size.
+- The driver schedules the DMA transfer via the ScheduleDMAtoHost API call.
+- The card raises the DMA Complete interrupt.
+- The driver checks the DMA status register for any errors.
+- The driver post-processes the newly transferred buffers.
+
+NOTE! It is possible that the Encoder and DMA Complete interrupts get raised
+simultaneously. (End of the last, start of the next, etc.)
+
+Mailbox #10
+===========
+
+The Flags, Command, Return Value and Timeout fields are ignored.
+
+Name:       Mailbox #10
+Results[0]: Type: 0: MPEG.
+Results[1]: Offset: The position relative to the card's memory space.
+Results[2]: Size: The exact number of bytes to transfer.
+
+My speculation is that since the StartCapture API has a capture type of "RAW"
+available, that the type field will have other values that correspond to YUV
+and PCM data.
+
+Scatter-Gather Array
+====================
+
+The scatter-gather array is a contiguously allocated block of memory that
+tells the card the source and destination of each data-block to transfer.
+Card "addresses" are derived from the offset supplied by Mailbox #10. Host
+addresses are the physical memory location of the target DMA buffer.
+
+Each S-G array element is a struct of three 32-bit words. The first word is
+the source address, the second is the destination address. Both take up the
+entire 32 bits. The lowest 16 bits of the third word is the transfer byte
+count. The high-bit of the third word is the "last" flag. The last-flag tells
+the card to raise the DMA_DONE interrupt. From hard personal experience, if
+you forget to set this bit, the card will still "work" but the stream will
+most likely get corrupted.
+
+The transfer count must be a multiple of 256. Therefore, the driver will need
+to track how much data in the target buffer is valid and deal with it
+accordingly.
+
+Array Element:
+
+- 32-bit Source Address
+- 32-bit Destination Address
+- 16-bit reserved (high bit is the last flag)
+- 16-bit byte count
+
+DMA Transfer Status
+===================
+
+Register 0x0004 holds the DMA Transfer Status:
+
+Bit
+4   Scatter-Gather array error
+3   DMA write error
+2   DMA read error
+1   write completed
+0   read completed

+ 694 - 0
Documentation/video4linux/cx2341x/fw-encoder-api.txt

@@ -0,0 +1,694 @@
+Encoder firmware API description
+================================
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_PING_FW
+Enum 	128/0x80
+Description
+	Does nothing. Can be used to check if the firmware is responding.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_START_CAPTURE
+Enum 	129/0x81
+Description
+	Commences the capture of video, audio and/or VBI data. All encoding
+	parameters must be initialized prior to this API call. Captures frames
+	continuously or until a predefined number of frames have been captured.
+Param[0]
+	Capture stream type:
+	    0=MPEG
+	    1=Raw
+	    2=Raw passthrough
+	    3=VBI
+
+Param[1]
+	Bitmask:
+	    Bit 0 when set, captures YUV
+	    Bit 1 when set, captures PCM audio
+	    Bit 2 when set, captures VBI (same as param[0]=3)
+	    Bit 3 when set, the capture destination is the decoder
+		(same as param[0]=2)
+	    Bit 4 when set, the capture destination is the host
+	Note: this parameter is only meaningful for RAW capture type.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_STOP_CAPTURE
+Enum 	130/0x82
+Description
+	Ends a capture in progress
+Param[0]
+	0=stop at end of GOP (generates IRQ)
+	1=stop immediate (no IRQ)
+Param[1]
+	Stream type to stop, see param[0] of API 0x81
+Param[2]
+	Subtype, see param[1] of API 0x81
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_AUDIO_ID
+Enum 	137/0x89
+Description
+	Assigns the transport stream ID of the encoded audio stream
+Param[0]
+	Audio Stream ID
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_VIDEO_ID
+Enum 	139/0x8B
+Description
+	Set video transport stream ID
+Param[0]
+	Video stream ID
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_PCR_ID
+Enum 	141/0x8D
+Description
+	Assigns the transport stream ID for PCR packets
+Param[0]
+	PCR Stream ID
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_FRAME_RATE
+Enum 	143/0x8F
+Description
+	Set video frames per second. Change occurs at start of new GOP.
+Param[0]
+	0=30fps
+	1=25fps
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_FRAME_SIZE
+Enum 	145/0x91
+Description
+	Select video stream encoding resolution.
+Param[0]
+	Height in lines. Default 480
+Param[1]
+	Width in pixels. Default 720
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_BIT_RATE
+Enum 	149/0x95
+Description
+	Assign average video stream bitrate. Note on the last three params:
+	Param[3] and [4] seem to be always 0, param [5] doesn't seem to be used.
+Param[0]
+	0=variable bitrate, 1=constant bitrate
+Param[1]
+	bitrate in bits per second
+Param[2]
+	peak bitrate in bits per second, divided by 400
+Param[3]
+	Mux bitrate in bits per second, divided by 400. May be 0 (default).
+Param[4]
+	Rate Control VBR Padding
+Param[5]
+	VBV Buffer used by encoder
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_GOP_PROPERTIES
+Enum 	151/0x97
+Description
+	Setup the GOP structure
+Param[0]
+	GOP size (maximum is 34)
+Param[1]
+	Number of B frames between the I and P frame, plus 1.
+	For example: IBBPBBPBBPBB --> GOP size: 12, number of B frames: 2+1 = 3
+	Note that GOP size must be a multiple of (B-frames + 1).
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_ASPECT_RATIO
+Enum 	153/0x99
+Description
+	Sets the encoding aspect ratio. Changes in the aspect ratio take effect
+	at the start of the next GOP.
+Param[0]
+	'0000' forbidden
+	'0001' 1:1 square
+	'0010' 4:3
+	'0011' 16:9
+	'0100' 2.21:1
+	'0101' reserved
+	 ....
+	'1111' reserved
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_DNR_FILTER_MODE
+Enum 	155/0x9B
+Description
+	Assign Dynamic Noise Reduction operating mode
+Param[0]
+	Bit0: Spatial filter, set=auto, clear=manual
+	Bit1: Temporal filter, set=auto, clear=manual
+Param[1]
+	Median filter:
+	    0=Disabled
+	    1=Horizontal
+	    2=Vertical
+	    3=Horiz/Vert
+	    4=Diagonal
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_DNR_FILTER_PROPS
+Enum 	157/0x9D
+Description
+	These Dynamic Noise Reduction filter values are only meaningful when
+	the respective filter is set to "manual" (See API 0x9B)
+Param[0]
+	Spatial filter: default 0, range 0:15
+Param[1]
+	Temporal filter: default 0, range 0:31
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_CORING_LEVELS
+Enum 	159/0x9F
+Description
+	Assign Dynamic Noise Reduction median filter properties.
+Param[0]
+	Threshold above which the luminance median filter is enabled.
+	Default: 0, range 0:255
+Param[1]
+	Threshold below which the luminance median filter is enabled.
+	Default: 255, range 0:255
+Param[2]
+	Threshold above which the chrominance median filter is enabled.
+	Default: 0, range 0:255
+Param[3]
+	Threshold below which the chrominance median filter is enabled.
+	Default: 255, range 0:255
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_SPATIAL_FILTER_TYPE
+Enum 	161/0xA1
+Description
+	Assign spatial prefilter parameters
+Param[0]
+	Luminance filter
+	    0=Off
+	    1=1D Horizontal
+	    2=1D Vertical
+	    3=2D H/V Separable (default)
+	    4=2D Symmetric non-separable
+Param[1]
+	Chrominance filter
+	    0=Off
+	    1=1D Horizontal (default)
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_3_2_PULLDOWN
+Enum 	177/0xB1
+Description
+	3:2 pulldown properties
+Param[0]
+	0=enabled
+	1=disabled
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_VBI_LINE
+Enum 	183/0xB7
+Description
+	Selects VBI line number.
+Param[0]
+	Bits 0:4 	line number
+	Bit  31		0=top_field, 1=bottom_field
+	Bits 0:31 	all set specifies "all lines"
+Param[1]
+	VBI line information features: 0=disabled, 1=enabled
+Param[2]
+	Slicing: 0=None, 1=Closed Caption
+	Almost certainly not implemented. Set to 0.
+Param[3]
+	Luminance samples in this line.
+	Almost certainly not implemented. Set to 0.
+Param[4]
+	Chrominance samples in this line
+	Almost certainly not implemented. Set to 0.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_STREAM_TYPE
+Enum 	185/0xB9
+Description
+	Assign stream type
+	Note: Transport stream is not working in recent firmwares.
+	And in older firmwares the timestamps in the TS seem to be
+	unreliable.
+Param[0]
+	 0=Program stream
+	 1=Transport stream
+	 2=MPEG1 stream
+	 3=PES A/V stream
+	 5=PES Video stream
+	 7=PES Audio stream
+	10=DVD stream
+	11=VCD stream
+	12=SVCD stream
+	13=DVD_S1 stream
+	14=DVD_S2 stream
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_OUTPUT_PORT
+Enum 	187/0xBB
+Description
+	Assign stream output port. Normally 0 when the data is copied through
+	the PCI bus (DMA), and 1 when the data is streamed to another chip
+	(pvrusb and cx88-blackbird).
+Param[0]
+	0=Memory (default)
+	1=Streaming
+	2=Serial
+Param[1]
+	Unknown, but leaving this to 0 seems to work best. Indications are that
+	this might have to do with USB support, although passing anything but 0
+	onl breaks things.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_AUDIO_PROPERTIES
+Enum 	189/0xBD
+Description
+	Set audio stream properties, may be called while encoding is in progress.
+	Note: all bitfields are consistent with ISO11172 documentation except
+	bits 2:3 which ISO docs define as:
+		'11' Layer I
+		'10' Layer II
+		'01' Layer III
+		'00' Undefined
+	This discrepancy may indicate a possible error in the documentation.
+	Testing indicated that only Layer II is actually working, and that
+	the minimum bitrate should be 192 kbps.
+Param[0]
+	Bitmask:
+	   0:1  '00' 44.1Khz
+		'01' 48Khz
+		'10' 32Khz
+		'11' reserved
+
+	   2:3  '01'=Layer I
+		'10'=Layer II
+
+	   4:7  Bitrate:
+		     Index | Layer I     | Layer II
+		     ------+-------------+------------
+		    '0000' | free format | free format
+		    '0001' |  32 kbit/s  |  32 kbit/s
+		    '0010' |  64 kbit/s  |  48 kbit/s
+		    '0011' |  96 kbit/s  |  56 kbit/s
+		    '0100' | 128 kbit/s  |  64 kbit/s
+		    '0101' | 160 kbit/s  |  80 kbit/s
+		    '0110' | 192 kbit/s  |  96 kbit/s
+		    '0111' | 224 kbit/s  | 112 kbit/s
+		    '1000' | 256 kbit/s  | 128 kbit/s
+		    '1001' | 288 kbit/s  | 160 kbit/s
+		    '1010' | 320 kbit/s  | 192 kbit/s
+		    '1011' | 352 kbit/s  | 224 kbit/s
+		    '1100' | 384 kbit/s  | 256 kbit/s
+		    '1101' | 416 kbit/s  | 320 kbit/s
+		    '1110' | 448 kbit/s  | 384 kbit/s
+		Note: For Layer II, not all combinations of total bitrate
+		and mode are allowed. See ISO11172-3 3-Annex B, Table 3-B.2
+
+	   8:9  '00'=Stereo
+		'01'=JointStereo
+		'10'=Dual
+		'11'=Mono
+		Note: testing seems to indicate that Mono and possibly
+		JointStereo are not working (default to stereo).
+		Dual does work, though.
+
+	  10:11 Mode Extension used in joint_stereo mode.
+		In Layer I and II they indicate which subbands are in
+		intensity_stereo. All other subbands are coded in stereo.
+		    '00' subbands 4-31 in intensity_stereo, bound==4
+		    '01' subbands 8-31 in intensity_stereo, bound==8
+		    '10' subbands 12-31 in intensity_stereo, bound==12
+		    '11' subbands 16-31 in intensity_stereo, bound==16
+
+	  12:13 Emphasis:
+		    '00' None
+		    '01' 50/15uS
+		    '10' reserved
+		    '11' CCITT J.17
+
+	  14 	CRC:
+		    '0' off
+		    '1' on
+
+	  15    Copyright:
+		    '0' off
+		    '1' on
+
+	  16    Generation:
+		    '0' copy
+		    '1' original
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_HALT_FW
+Enum 	195/0xC3
+Description
+	The firmware is halted and no further API calls are serviced until the
+	firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_GET_VERSION
+Enum 	196/0xC4
+Description
+	Returns the version of the encoder firmware.
+Result[0]
+	Version bitmask:
+	    Bits  0:15 build
+	    Bits 16:23 minor
+	    Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_GOP_CLOSURE
+Enum 	197/0xC5
+Description
+	Assigns the GOP open/close property.
+Param[0]
+	0=Open
+	1=Closed
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_GET_SEQ_END
+Enum 	198/0xC6
+Description
+	Obtains the sequence end code of the encoder's buffer. When a capture
+	is started a number of interrupts are still generated, the last of
+	which will have Result[0] set to 1 and Result[1] will contain the size
+	of the buffer.
+Result[0]
+	State of the transfer (1 if last buffer)
+Result[1]
+	If Result[0] is 1, this contains the size of the last buffer, undefined
+	otherwise.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_PGM_INDEX_INFO
+Enum 	199/0xC7
+Description
+	Sets the Program Index Information.
+Param[0]
+	Picture Mask:
+	    0=No index capture
+	    1=I frames
+	    3=I,P frames
+	    7=I,P,B frames
+Param[1]
+	Elements requested (up to 400)
+Result[0]
+	Offset in SDF memory of the table.
+Result[1]
+	Number of allocated elements up to a maximum of Param[1]
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_VBI_CONFIG
+Enum 	200/0xC8
+Description
+	Configure VBI settings
+Param[0]
+	Bitmap:
+	    0    Mode '0' Sliced, '1' Raw
+	    1:3  Insertion:
+		     '000' insert in extension & user data
+		     '001' insert in private packets
+		     '010' separate stream and user data
+		     '111' separate stream and private data
+	    8:15 Stream ID (normally 0xBD)
+Param[1]
+	Frames per interrupt (max 8). Only valid in raw mode.
+Param[2]
+	Total raw VBI frames. Only valid in raw mode.
+Param[3]
+	Start codes
+Param[4]
+	Stop codes
+Param[5]
+	Lines per frame
+Param[6]
+	Byte per line
+Result[0]
+	Observed frames per interrupt in raw mode only. Rage 1 to Param[1]
+Result[1]
+	Observed number of frames in raw mode. Range 1 to Param[2]
+Result[2]
+	Memory offset to start or raw VBI data
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_DMA_BLOCK_SIZE
+Enum 	201/0xC9
+Description
+	Set DMA transfer block size
+Param[0]
+	DMA transfer block size in bytes or frames. When unit is bytes,
+	supported block sizes are 2^7, 2^8 and 2^9 bytes.
+Param[1]
+	Unit: 0=bytes, 1=frames
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_GET_PREV_DMA_INFO_MB_10
+Enum 	202/0xCA
+Description
+	Returns information on the previous DMA transfer in conjunction with
+	bit 27 of the interrupt mask. Uses mailbox 10.
+Result[0]
+	Type of stream
+Result[1]
+	Address Offset
+Result[2]
+	Maximum size of transfer
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_GET_PREV_DMA_INFO_MB_9
+Enum 	203/0xCB
+Description
+	Returns information on the previous DMA transfer in conjunction with
+	bit 27 of the interrupt mask. Uses mailbox 9.
+Result[0]
+	Status bits:
+	    Bit 0 set indicates transfer complete
+	    Bit 2 set indicates transfer error
+	    Bit 4 set indicates linked list error
+Result[1]
+	DMA type
+Result[2]
+	Presentation Time Stamp bits 0..31
+Result[3]
+	Presentation Time Stamp bit 32
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SCHED_DMA_TO_HOST
+Enum 	204/0xCC
+Description
+	Setup DMA to host operation
+Param[0]
+	Memory address of link list
+Param[1]
+	Length of link list (wtf: what units ???)
+Param[2]
+	DMA type (0=MPEG)
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_INITIALIZE_INPUT
+Enum 	205/0xCD
+Description
+	Initializes the video input
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_FRAME_DROP_RATE
+Enum 	208/0xD0
+Description
+	For each frame captured, skip specified number of frames.
+Param[0]
+	Number of frames to skip
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_PAUSE_ENCODER
+Enum 	210/0xD2
+Description
+	During a pause condition, all frames are dropped instead of being encoded.
+Param[0]
+	0=Pause encoding
+	1=Continue encoding
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_REFRESH_INPUT
+Enum 	211/0xD3
+Description
+	Refreshes the video input
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_COPYRIGHT
+Enum 	212/0xD4
+Description
+	Sets stream copyright property
+Param[0]
+	0=Stream is not copyrighted
+	1=Stream is copyrighted
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_EVENT_NOTIFICATION
+Enum 	213/0xD5
+Description
+	Setup firmware to notify the host about a particular event. Host must
+	unmask the interrupt bit.
+Param[0]
+	Event (0=refresh encoder input)
+Param[1]
+	Notification 0=disabled 1=enabled
+Param[2]
+	Interrupt bit
+Param[3]
+	Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_NUM_VSYNC_LINES
+Enum 	214/0xD6
+Description
+	Depending on the analog video decoder used, this assigns the number
+	of lines for field 1 and 2.
+Param[0]
+	Field 1 number of lines:
+	    0x00EF for SAA7114
+	    0x00F0 for SAA7115
+	    0x0105 for Micronas
+Param[1]
+	Field 2 number of lines:
+	    0x00EF for SAA7114
+	    0x00F0 for SAA7115
+	    0x0106 for Micronas
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_PLACEHOLDER
+Enum 	215/0xD7
+Description
+	Provides a mechanism of inserting custom user data in the MPEG stream.
+Param[0]
+	0=extension & user data
+	1=private packet with stream ID 0xBD
+Param[1]
+	Rate at which to insert data, in units of frames (for private packet)
+	or GOPs (for ext. & user data)
+Param[2]
+	Number of data DWORDs (below) to insert
+Param[3]
+	Custom data 0
+Param[4]
+	Custom data 1
+Param[5]
+	Custom data 2
+Param[6]
+	Custom data 3
+Param[7]
+	Custom data 4
+Param[8]
+	Custom data 5
+Param[9]
+	Custom data 6
+Param[10]
+	Custom data 7
+Param[11]
+	Custom data 8
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_MUTE_VIDEO
+Enum 	217/0xD9
+Description
+	Video muting
+Param[0]
+	Bit usage:
+	 0    	'0'=video not muted
+		'1'=video muted, creates frames with the YUV color defined below
+	 1:7  	Unused
+	 8:15 	V chrominance information
+	16:23 	U chrominance information
+	24:31 	Y luminance information
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_MUTE_AUDIO
+Enum 	218/0xDA
+Description
+	Audio muting
+Param[0]
+	0=audio not muted
+	1=audio muted (produces silent mpeg audio stream)
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_UNKNOWN
+Enum 	219/0xDB
+Description
+	Unknown API, it's used by Hauppauge though.
+Param[0]
+	0 This is the value Hauppauge uses, Unknown what it means.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_MISC
+Enum 	220/0xDC
+Description
+	Miscellaneous actions. Not known for 100% what it does. It's really a
+	sort of ioctl call. The first parameter is a command number, the second
+	the value.
+Param[0]
+	Command number:
+	 1=set initial SCR value when starting encoding.
+	 2=set quality mode (apparently some test setting).
+	 3=setup advanced VIM protection handling (supposedly only for the cx23416
+	   for raw YUV).
+	   Actually it looks like this should be 0 for saa7114/5 based card and 1
+	   for cx25840 based cards.
+	 4=generate artificial PTS timestamps
+	 5=USB flush mode
+	 6=something to do with the quantization matrix
+	 7=set navigation pack insertion for DVD
+	 8=enable scene change detection (seems to be a failure)
+	 9=set history parameters of the video input module
+	10=set input field order of VIM
+	11=set quantization matrix
+	12=reset audio interface
+	13=set audio volume delay
+	14=set audio delay
+
+Param[1]
+	Command value.

+ 141 - 0
Documentation/video4linux/cx2341x/fw-memory.txt

@@ -0,0 +1,141 @@
+This document describes the cx2341x memory map and documents some of the register
+space.
+
+Warning! This information was figured out from searching through the memory and
+registers, this information may not be correct and is certainly not complete, and
+was not derived from anything more than searching through the memory space with
+commands like:
+
+	ivtvctl -O min=0x02000000,max=0x020000ff
+
+So take this as is, I'm always searching for more stuff, it's a large
+register space :-).
+
+Memory Map
+==========
+
+The cx2341x exposes its entire 64M memory space to the PCI host via the PCI BAR0
+(Base Address Register 0). The addresses here are offsets relative to the
+address held in BAR0.
+
+0x00000000-0x00ffffff Encoder memory space
+0x00000000-0x0003ffff Encode.rom
+      ???-???         MPEG buffer(s)
+      ???-???         Raw video capture buffer(s)
+      ???-???         Raw audio capture buffer(s)
+      ???-???         Display buffers (6 or 9)
+
+0x01000000-0x01ffffff Decoder memory space
+0x01000000-0x0103ffff Decode.rom
+      ???-???         MPEG buffers(s)
+0x0114b000-0x0115afff Audio.rom (deprecated?)
+
+0x02000000-0x0200ffff Register Space
+
+Registers
+=========
+
+The registers occupy the 64k space starting at the 0x02000000 offset from BAR0.
+All of these registers are 32 bits wide.
+
+DMA Registers 0x000-0xff:
+
+ 0x00 - Control:
+	0=reset/cancel, 1=read, 2=write, 4=stop
+ 0x04 - DMA status:
+	1=read busy, 2=write busy, 4=read error, 8=write error, 16=link list error
+ 0x08 - pci DMA pointer for read link list
+ 0x0c - pci DMA pointer for write link list
+ 0x10 - read/write DMA enable:
+	1=read enable, 2=write enable
+ 0x14 - always 0xffffffff, if set any lower instability occurs, 0x00 crashes
+ 0x18 - ??
+ 0x1c - always 0x20 or 32, smaller values slow down DMA transactions
+ 0x20 - always value of 0x780a010a
+ 0x24-0x3c - usually just random values???
+ 0x40 - Interrupt status
+ 0x44 - Write a bit here and shows up in Interrupt status 0x40
+ 0x48 - Interrupt Mask
+ 0x4C - always value of 0xfffdffff,
+	if changed to 0xffffffff DMA write interrupts break.
+ 0x50 - always 0xffffffff
+ 0x54 - always 0xffffffff (0x4c, 0x50, 0x54 seem like interrupt masks, are
+	3 processors on chip, Java ones, VPU, SPU, APU, maybe these are the
+	interrupt masks???).
+ 0x60-0x7C - random values
+ 0x80 - first write linked list reg, for Encoder Memory addr
+ 0x84 - first write linked list reg, for pci memory addr
+ 0x88 - first write linked list reg, for length of buffer in memory addr
+	(|0x80000000 or this for last link)
+ 0x8c-0xcc - rest of write linked list reg, 8 sets of 3 total, DMA goes here
+	from linked list addr in reg 0x0c, firmware must push through or
+	something.
+ 0xe0 - first (and only) read linked list reg, for pci memory addr
+ 0xe4 - first (and only) read linked list reg, for Decoder memory addr
+ 0xe8 - first (and only) read linked list reg, for length of buffer
+ 0xec-0xff - Nothing seems to be in these registers, 0xec-f4 are 0x00000000.
+
+Memory locations for Encoder Buffers 0x700-0x7ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for encoding, have to shift them by <<1 first.
+
+0x07F8: Encoder SDRAM refresh
+0x07FC: Encoder SDRAM pre-charge
+
+Memory locations for Decoder Buffers 0x800-0x8ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for decoding, have to shift them by <<1 first.
+
+0x08F8: Decoder SDRAM refresh
+0x08FC: Decoder SDRAM pre-charge
+
+Other memory locations:
+
+0x2800: Video Display Module control
+0x2D00: AO (audio output?) control
+0x2D24: Bytes Flushed
+0x7000: LSB I2C write clock bit (inverted)
+0x7004: LSB I2C write data bit (inverted)
+0x7008: LSB I2C read clock bit
+0x700c: LSB I2C read data bit
+0x9008: GPIO get input state
+0x900c: GPIO set output state
+0x9020: GPIO direction (Bit7 (GPIO 0..7) - 0:input, 1:output)
+0x9050: SPU control
+0x9054: Reset HW blocks
+0x9058: VPU control
+0xA018: Bit6: interrupt pending?
+0xA064: APU command
+
+
+Interrupt Status Register
+=========================
+
+The definition of the bits in the interrupt status register 0x0040, and the
+interrupt mask 0x0048. If a bit is cleared in the mask, then we want our ISR to
+execute.
+
+Bit
+31 Encoder Start Capture
+30 Encoder EOS
+29 Encoder VBI capture
+28 Encoder Video Input Module reset event
+27 Encoder DMA complete
+26
+25 Decoder copy protect detection event
+24 Decoder audio mode change detection event
+23
+22 Decoder data request
+21 Decoder I-Frame? done
+20 Decoder DMA complete
+19 Decoder VBI re-insertion
+18 Decoder DMA err (linked-list bad)
+
+Missing
+Encoder API call completed
+Decoder API call completed
+Encoder API post(?)
+Decoder API post(?)
+Decoder VTRACE event

+ 342 - 0
Documentation/video4linux/cx2341x/fw-osd-api.txt

@@ -0,0 +1,342 @@
+OSD firmware API description
+============================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_FRAMEBUFFER
+Enum 	65/0x41
+Description
+	Return base and length of contiguous OSD memory.
+Result[0]
+	OSD base address
+Result[1]
+	OSD length
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_PIXEL_FORMAT
+Enum 	66/0x42
+Description
+	Query OSD format
+Result[0]
+	0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_PIXEL_FORMAT
+Enum 	67/0x43
+Description
+	Assign pixel format
+Param[0]
+	0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_STATE
+Enum 	68/0x44
+Description
+	Query OSD state
+Result[0]
+	Bit  0   0=off, 1=on
+	Bits 1:2 alpha control
+	Bits 3:5 pixel format
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_STATE
+Enum 	69/0x45
+Description
+	OSD switch
+Param[0]
+	0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_OSD_COORDS
+Enum 	70/0x46
+Description
+	Retrieve coordinates of OSD area blended with video
+Result[0]
+	OSD buffer address
+Result[1]
+	Stride in pixels
+Result[2]
+	Lines in OSD buffer
+Result[3]
+	Horizontal offset in buffer
+Result[4]
+	Vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_OSD_COORDS
+Enum 	71/0x47
+Description
+	Assign the coordinates of the OSD area to blend with video
+Param[0]
+	buffer address
+Param[1]
+	buffer stride in pixels
+Param[2]
+	lines in buffer
+Param[3]
+	horizontal offset
+Param[4]
+	vertical offset
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_SCREEN_COORDS
+Enum 	72/0x48
+Description
+	Retrieve OSD screen area coordinates
+Result[0]
+	top left horizontal offset
+Result[1]
+	top left vertical offset
+Result[2]
+	bottom right hotizontal offset
+Result[3]
+	bottom right vertical offset
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_SCREEN_COORDS
+Enum 	73/0x49
+Description
+	Assign the coordinates of the screen area to blend with video
+Param[0]
+	top left horizontal offset
+Param[1]
+	top left vertical offset
+Param[2]
+	bottom left horizontal offset
+Param[3]
+	bottom left vertical offset
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_GLOBAL_ALPHA
+Enum 	74/0x4A
+Description
+	Retrieve OSD global alpha
+Result[0]
+	global alpha: 0=off, 1=on
+Result[1]
+	bits 0:7 global alpha
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_GLOBAL_ALPHA
+Enum 	75/0x4B
+Description
+	Update global alpha
+Param[0]
+	global alpha: 0=off, 1=on
+Param[1]
+	global alpha (8 bits)
+Param[2]
+	local alpha: 0=on, 1=off
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_BLEND_COORDS
+Enum 	78/0x4C
+Description
+	Move start of blending area within display buffer
+Param[0]
+	horizontal offset in buffer
+Param[1]
+	vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_FLICKER_STATE
+Enum 	79/0x4F
+Description
+	Retrieve flicker reduction module state
+Result[0]
+	flicker state: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_FLICKER_STATE
+Enum 	80/0x50
+Description
+	Set flicker reduction module state
+Param[0]
+	State: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_BLT_COPY
+Enum 	82/0x52
+Description
+	BLT copy
+Param[0]
+'0000'  zero
+'0001' ~destination AND ~source
+'0010' ~destination AND  source
+'0011' ~destination
+'0100'  destination AND ~source
+'0101'                  ~source
+'0110'  destination XOR  source
+'0111' ~destination OR  ~source
+'1000' ~destination AND ~source
+'1001'  destination XNOR source
+'1010'                   source
+'1011' ~destination OR   source
+'1100'  destination
+'1101'  destination OR  ~source
+'1110'  destination OR   source
+'1111'  one
+
+Param[1]
+	Resulting alpha blending
+	    '01' source_alpha
+	    '10' destination_alpha
+	    '11' source_alpha*destination_alpha+1
+		 (zero if both source and destination alpha are zero)
+Param[2]
+	'00' output_pixel = source_pixel
+
+	'01' if source_alpha=0:
+		 output_pixel = destination_pixel
+	     if 256 > source_alpha > 1:
+		 output_pixel = ((source_alpha + 1)*source_pixel +
+				 (255 - source_alpha)*destination_pixel)/256
+
+	'10' if destination_alpha=0:
+		 output_pixel = source_pixel
+	      if 255 > destination_alpha > 0:
+		 output_pixel = ((255 - destination_alpha)*source_pixel +
+				 (destination_alpha + 1)*destination_pixel)/256
+
+	'11' if source_alpha=0:
+		 source_temp = 0
+	     if source_alpha=255:
+		 source_temp = source_pixel*256
+	     if 255 > source_alpha > 0:
+		 source_temp = source_pixel*(source_alpha + 1)
+	     if destination_alpha=0:
+		 destination_temp = 0
+	     if destination_alpha=255:
+		 destination_temp = destination_pixel*256
+	     if 255 > destination_alpha > 0:
+		 destination_temp = destination_pixel*(destination_alpha + 1)
+	     output_pixel = (source_temp + destination_temp)/256
+Param[3]
+	width
+Param[4]
+	height
+Param[5]
+	destination pixel mask
+Param[6]
+	destination rectangle start address
+Param[7]
+	destination stride in dwords
+Param[8]
+	source stride in dwords
+Param[9]
+	source rectangle start address
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_BLT_FILL
+Enum 	83/0x53
+Description
+	BLT fill color
+Param[0]
+	Same as Param[0] on API 0x52
+Param[1]
+	Same as Param[1] on API 0x52
+Param[2]
+	Same as Param[2] on API 0x52
+Param[3]
+	width
+Param[4]
+	height
+Param[5]
+	destination pixel mask
+Param[6]
+	destination rectangle start address
+Param[7]
+	destination stride in dwords
+Param[8]
+	color fill value
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_BLT_TEXT
+Enum 	84/0x54
+Description
+	BLT for 8 bit alpha text source
+Param[0]
+	Same as Param[0] on API 0x52
+Param[1]
+	Same as Param[1] on API 0x52
+Param[2]
+	Same as Param[2] on API 0x52
+Param[3]
+	width
+Param[4]
+	height
+Param[5]
+	destination pixel mask
+Param[6]
+	destination rectangle start address
+Param[7]
+	destination stride in dwords
+Param[8]
+	source stride in dwords
+Param[9]
+	source rectangle start address
+Param[10]
+	color fill value
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_FRAMEBUFFER_WINDOW
+Enum 	86/0x56
+Description
+	Positions the main output window on the screen. The coordinates must be
+	such that the entire window fits on the screen.
+Param[0]
+	window width
+Param[1]
+	window height
+Param[2]
+	top left window corner horizontal offset
+Param[3]
+	top left window corner vertical offset
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_CHROMA_KEY
+Enum 	96/0x60
+Description
+	Chroma key switch and color
+Param[0]
+	state: 0=off, 1=on
+Param[1]
+	color
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_ALPHA_CONTENT_INDEX
+Enum 	97/0x61
+Description
+	Retrieve alpha content index
+Result[0]
+	alpha content index, Range 0:15
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_ALPHA_CONTENT_INDEX
+Enum 	98/0x62
+Description
+	Assign alpha content index
+Param[0]
+	alpha content index, range 0:15

+ 49 - 0
Documentation/video4linux/cx2341x/fw-upload.txt

@@ -0,0 +1,49 @@
+This document describes how to upload the cx2341x firmware to the card.
+
+How to find
+===========
+
+See the web pages of the various projects that uses this chip for information
+on how to obtain the firmware.
+
+The firmware stored in a Windows driver can be detected as follows:
+
+- Each firmware image is 256k bytes.
+- The 1st 32-bit word of the Encoder image is 0x0000da7
+- The 1st 32-bit word of the Decoder image is 0x00003a7
+- The 2nd 32-bit word of both images is 0xaa55bb66
+
+How to load
+===========
+
+- Issue the FWapi command to stop the encoder if it is running. Wait for the
+  command to complete.
+- Issue the FWapi command to stop the decoder if it is running. Wait for the
+  command to complete.
+- Issue the I2C command to the digitizer to stop emitting VSYNC events.
+- Issue the FWapi command to halt the encoder's firmware.
+- Sleep for 10ms.
+- Issue the FWapi command to halt the decoder's firmware.
+- Sleep for 10ms.
+- Write 0x00000000 to register 0x2800 to stop the Video Display Module.
+- Write 0x00000005 to register 0x2D00 to stop the AO (audio output?).
+- Write 0x00000000 to register 0xA064 to ping? the APU.
+- Write 0xFFFFFFFE to register 0x9058 to stop the VPU.
+- Write 0xFFFFFFFF to register 0x9054 to reset the HW blocks.
+- Write 0x00000001 to register 0x9050 to stop the SPU.
+- Sleep for 10ms.
+- Write 0x0000001A to register 0x07FC to init the Encoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x07F8 to init the Encoder SDRAM's refresh to 1us.
+- Write 0x0000001A to register 0x08FC to init the Decoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x08F8 to init the Decoder SDRAM's refresh to 1us.
+- Sleep for 512ms. (600ms is recommended)
+- Transfer the encoder's firmware image to offset 0 in Encoder memory space.
+- Transfer the decoder's firmware image to offset 0 in Decoder memory space.
+- Use a read-modify-write operation to Clear bit 0 of register 0x9050 to
+  re-enable the SPU.
+- Sleep for 1 second.
+- Use a read-modify-write operation to Clear bits 3 and 0 of register 0x9058
+  to re-enable the VPU.
+- Sleep for 1 second.
+- Issue status API commands to both firmware images to verify.
+

+ 54 - 0
Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt

@@ -0,0 +1,54 @@
+The controls for the mux are GPIO [0,1] for source, and GPIO 2 for muting.
+
+GPIO0  GPIO1
+  0        0    TV Audio
+  1        0    FM radio
+  0        1    Line-In
+  1        1    Mono tuner bypass or CD passthru (tuner specific)
+
+GPIO 16(i believe) is tied to the IR port (if present).
+
+------------------------------------------------------------------------------------
+
+>From the data sheet:
+ Register 24'h20004  PCI Interrupt Status
+  bit [18]  IR_SMP_INT Set when 32 input samples have been collected over
+  gpio[16] pin into GP_SAMPLE register.
+
+What's missing from the data sheet:
+
+Setup 4KHz sampling rate (roughly 2x oversampled; good enough for our RC5
+compat remote)
+set register 0x35C050 to  0xa80a80
+
+enable sampling
+set register 0x35C054 to 0x5
+
+Of course, enable the IRQ bit 18 in the interrupt mask register .(and
+provide for a handler)
+
+GP_SAMPLE register is at 0x35C058
+
+Bits are then right shifted into the GP_SAMPLE register at the specified
+rate; you get an interrupt when a full DWORD is recieved.
+You need to recover the actual RC5 bits out of the (oversampled) IR sensor
+bits. (Hint: look for the 0/1and 1/0 crossings of the RC5 bi-phase data)  An
+actual raw RC5 code will span 2-3 DWORDS, depending on the actual alignment.
+
+I'm pretty sure when no IR signal is present the receiver is always in a
+marking state(1); but stray light, etc can cause intermittent noise values
+as well.  Remember, this is a free running sample of the IR receiver state
+over time, so don't assume any sample starts at any particular place.
+
+http://www.atmel.com/dyn/resources/prod_documents/doc2817.pdf
+This data sheet (google search) seems to have a lovely description of the
+RC5 basics
+
+http://users.pandora.be/nenya/electronics/rc5/  and more data
+
+http://www.ee.washington.edu/circuit_archive/text/ir_decode.txt
+and even a reference to how to decode a bi-phase data stream.
+
+http://www.xs4all.nl/~sbp/knowledge/ir/rc5.htm
+still more info
+

+ 26 - 26
Documentation/video4linux/et61x251.txt

@@ -1,9 +1,9 @@
 
-                       ET61X[12]51 PC Camera Controllers
-                                Driver for Linux
-                       =================================
+		       ET61X[12]51 PC Camera Controllers
+				Driver for Linux
+		       =================================
 
-                               - Documentation -
+			       - Documentation -
 
 
 Index
@@ -156,46 +156,46 @@ Name:           video_nr
 Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L2 minor mode number:
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 64 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                registered camera and use auto for the first one and for every
-                other camera.
+		-1 = use next available
+		 n = use minor number n
+		You can specify up to 64 cameras this way.
+		For example:
+		video_nr=-1,2,-1 would assign minor number 2 to the second
+		registered camera and use auto for the first one and for every
+		other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]>
 Description:    Force the application to unmap previously mapped buffer memory
-                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
-                all the applications support this feature. This parameter is
-                specific for each detected camera.
-                0 = do not force memory unmapping
-                1 = force memory unmapping (save memory)
+		before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+		all the applications support this feature. This parameter is
+		specific for each detected camera.
+		0 = do not force memory unmapping
+		1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           frame_timeout
 Type:           uint array (min = 0, max = 64)
 Syntax:         <n[,...]>
 Description:    Timeout for a video frame in seconds. This parameter is
-                specific for each detected camera. This parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		specific for each detected camera. This parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 3:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = more verbose messages
-                Level 3 is useful for testing only, when only one device
-                is used at the same time. It also shows some more informations
-                about the hardware being detected. This module parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		0 = none (use carefully)
+		1 = critical errors
+		2 = significant informations
+		3 = more verbose messages
+		Level 3 is useful for testing only, when only one device
+		is used at the same time. It also shows some more informations
+		about the hardware being detected. This module parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 

+ 84 - 84
Documentation/video4linux/ibmcam.txt

@@ -21,7 +21,7 @@ Internal interface: Video For Linux (V4L)
 Supported controls:
 - by V4L: Contrast,  Brightness, Color, Hue
 - by driver options: frame rate, lighting conditions, video format,
-                     default picture settings, sharpness.
+		     default picture settings, sharpness.
 
 SUPPORTED CAMERAS:
 
@@ -191,66 +191,66 @@ init_model2_sat Integer         0..255 [0x34]   init_model2_sat=65
 init_model2_yb  Integer         0..255 [0xa0]   init_model2_yb=200
 
 debug           You don't need this option unless you are a developer.
-                If you are a developer then you will see in the code
-                what values do what. 0=off.
+		If you are a developer then you will see in the code
+		what values do what. 0=off.
 
 flags           This is a bit mask, and you can combine any number of
-                bits to produce what you want. Usually you don't want
-                any of extra features this option provides:
-
-                FLAGS_RETRY_VIDIOCSYNC  1  This bit allows to retry failed
-                                           VIDIOCSYNC ioctls without failing.
-                                           Will work with xawtv, will not
-                                           with xrealproducer. Default is
-                                           not set.
-                FLAGS_MONOCHROME        2  Activates monochrome (b/w) mode.
-                FLAGS_DISPLAY_HINTS     4  Shows colored pixels which have
-                                           magic meaning to developers.
-                FLAGS_OVERLAY_STATS     8  Shows tiny numbers on screen,
-                                           useful only for debugging.
-                FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
-                FLAGS_SEPARATE_FRAMES   32 Shows each frame separately, as
-                                           it was received from the camera.
-                                           Default (not set) is to mix the
-                                           preceding frame in to compensate
-                                           for occasional loss of Isoc data
-                                           on high frame rates.
-                FLAGS_CLEAN_FRAMES      64 Forces "cleanup" of each frame
-                                           prior to use; relevant only if
-                                           FLAGS_SEPARATE_FRAMES is set.
-                                           Default is not to clean frames,
-                                           this is a little faster but may
-                                           produce flicker if frame rate is
-                                           too high and Isoc data gets lost.
-                FLAGS_NO_DECODING      128 This flag turns the video stream
-                                           decoder off, and dumps the raw
-                                           Isoc data from the camera into
-                                           the reading process. Useful to
-                                           developers, but not to users.
+		bits to produce what you want. Usually you don't want
+		any of extra features this option provides:
+
+		FLAGS_RETRY_VIDIOCSYNC  1  This bit allows to retry failed
+					   VIDIOCSYNC ioctls without failing.
+					   Will work with xawtv, will not
+					   with xrealproducer. Default is
+					   not set.
+		FLAGS_MONOCHROME        2  Activates monochrome (b/w) mode.
+		FLAGS_DISPLAY_HINTS     4  Shows colored pixels which have
+					   magic meaning to developers.
+		FLAGS_OVERLAY_STATS     8  Shows tiny numbers on screen,
+					   useful only for debugging.
+		FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
+		FLAGS_SEPARATE_FRAMES   32 Shows each frame separately, as
+					   it was received from the camera.
+					   Default (not set) is to mix the
+					   preceding frame in to compensate
+					   for occasional loss of Isoc data
+					   on high frame rates.
+		FLAGS_CLEAN_FRAMES      64 Forces "cleanup" of each frame
+					   prior to use; relevant only if
+					   FLAGS_SEPARATE_FRAMES is set.
+					   Default is not to clean frames,
+					   this is a little faster but may
+					   produce flicker if frame rate is
+					   too high and Isoc data gets lost.
+		FLAGS_NO_DECODING      128 This flag turns the video stream
+					   decoder off, and dumps the raw
+					   Isoc data from the camera into
+					   the reading process. Useful to
+					   developers, but not to users.
 
 framerate       This setting controls frame rate of the camera. This is
-                an approximate setting (in terms of "worst" ... "best")
-                because camera changes frame rate depending on amount
-                of light available. Setting 0 is slowest, 6 is fastest.
-                Beware - fast settings are very demanding and may not
-                work well with all video sizes. Be conservative.
+		an approximate setting (in terms of "worst" ... "best")
+		because camera changes frame rate depending on amount
+		of light available. Setting 0 is slowest, 6 is fastest.
+		Beware - fast settings are very demanding and may not
+		work well with all video sizes. Be conservative.
 
 hue_correction  This highly optional setting allows to adjust the
-                hue of the image in a way slightly different from
-                what usual "hue" control does. Both controls affect
-                YUV colorspace: regular "hue" control adjusts only
-                U component, and this "hue_correction" option similarly
-                adjusts only V component. However usually it is enough
-                to tweak only U or V to compensate for colored light or
-                color temperature; this option simply allows more
-                complicated correction when and if it is necessary.
+		hue of the image in a way slightly different from
+		what usual "hue" control does. Both controls affect
+		YUV colorspace: regular "hue" control adjusts only
+		U component, and this "hue_correction" option similarly
+		adjusts only V component. However usually it is enough
+		to tweak only U or V to compensate for colored light or
+		color temperature; this option simply allows more
+		complicated correction when and if it is necessary.
 
 init_brightness These settings specify _initial_ values which will be
 init_contrast   used to set up the camera. If your V4L application has
 init_color      its own controls to adjust the picture then these
 init_hue        controls will be used too. These options allow you to
-                preconfigure the camera when it gets connected, before
-                any V4L application connects to it. Good for webcams.
+		preconfigure the camera when it gets connected, before
+		any V4L application connects to it. Good for webcams.
 
 init_model2_rg  These initial settings alter color balance of the
 init_model2_rg2 camera on hardware level. All four settings may be used
@@ -258,47 +258,47 @@ init_model2_sat to tune the camera to specific lighting conditions. These
 init_model2_yb  settings only apply to Model 2 cameras.
 
 lighting        This option selects one of three hardware-defined
-                photosensitivity settings of the camera. 0=bright light,
-                1=Medium (default), 2=Low light. This setting affects
-                frame rate: the dimmer the lighting the lower the frame
-                rate (because longer exposition time is needed). The
-                Model 2 cameras allow values more than 2 for this option,
-                thus enabling extremely high sensitivity at cost of frame
-                rate, color saturation and imaging sensor noise.
+		photosensitivity settings of the camera. 0=bright light,
+		1=Medium (default), 2=Low light. This setting affects
+		frame rate: the dimmer the lighting the lower the frame
+		rate (because longer exposition time is needed). The
+		Model 2 cameras allow values more than 2 for this option,
+		thus enabling extremely high sensitivity at cost of frame
+		rate, color saturation and imaging sensor noise.
 
 sharpness       This option controls smoothing (noise reduction)
-                made by camera. Setting 0 is most smooth, setting 6
-                is most sharp. Be aware that CMOS sensor used in the
-                camera is pretty noisy, so if you choose 6 you will
-                be greeted with "snowy" image. Default is 4. Model 2
-                cameras do not support this feature.
+		made by camera. Setting 0 is most smooth, setting 6
+		is most sharp. Be aware that CMOS sensor used in the
+		camera is pretty noisy, so if you choose 6 you will
+		be greeted with "snowy" image. Default is 4. Model 2
+		cameras do not support this feature.
 
 size            This setting chooses one of several image sizes that are
-                supported by this driver. Cameras may support more, but
-                it's difficult to reverse-engineer all formats.
-                Following video sizes are supported:
-
-                size=0     128x96  (Model 1 only)
-                size=1     160x120
-                size=2     176x144
-                size=3     320x240 (Model 2 only)
-                size=4     352x240 (Model 2 only)
-                size=5     352x288
-                size=6     640x480 (Model 3 only)
-
-                The 352x288 is the native size of the Model 1 sensor
-                array, so it's the best resolution the camera can
-                yield. The best resolution of Model 2 is 176x144, and
-                larger images are produced by stretching the bitmap.
-                Model 3 has sensor with 640x480 grid, and it works too,
-                but the frame rate will be exceptionally low (1-2 FPS);
-                it may be still OK for some applications, like security.
-                Choose the image size you need. The smaller image can
-                support faster frame rate. Default is 352x288.
+		supported by this driver. Cameras may support more, but
+		it's difficult to reverse-engineer all formats.
+		Following video sizes are supported:
+
+		size=0     128x96  (Model 1 only)
+		size=1     160x120
+		size=2     176x144
+		size=3     320x240 (Model 2 only)
+		size=4     352x240 (Model 2 only)
+		size=5     352x288
+		size=6     640x480 (Model 3 only)
+
+		The 352x288 is the native size of the Model 1 sensor
+		array, so it's the best resolution the camera can
+		yield. The best resolution of Model 2 is 176x144, and
+		larger images are produced by stretching the bitmap.
+		Model 3 has sensor with 640x480 grid, and it works too,
+		but the frame rate will be exceptionally low (1-2 FPS);
+		it may be still OK for some applications, like security.
+		Choose the image size you need. The smaller image can
+		support faster frame rate. Default is 352x288.
 
 For more information and the Troubleshooting FAQ visit this URL:
 
-                http://www.linux-usb.org/ibmcam/
+		http://www.linux-usb.org/ibmcam/
 
 WHAT NEEDS TO BE DONE:
 

+ 16 - 16
Documentation/video4linux/ov511.txt

@@ -81,7 +81,7 @@ MODULE PARAMETERS:
   TYPE: integer (Boolean)
   DEFAULT: 1
   DESC: Brightness is normally under automatic control and can't be set
-        manually by the video app. Set to 0 for manual control.
+	manually by the video app. Set to 0 for manual control.
 
   NAME: autogain
   TYPE: integer (Boolean)
@@ -97,13 +97,13 @@ MODULE PARAMETERS:
   TYPE: integer (0-6)
   DEFAULT: 3
   DESC: Sets the threshold for printing debug messages. The higher the value,
-        the more is printed. The levels are cumulative, and are as follows:
-          0=no debug messages
-          1=init/detection/unload and other significant messages
-          2=some warning messages
-          3=config/control function calls
-          4=most function calls and data parsing messages
-          5=highly repetitive mesgs
+	the more is printed. The levels are cumulative, and are as follows:
+	  0=no debug messages
+	  1=init/detection/unload and other significant messages
+	  2=some warning messages
+	  3=config/control function calls
+	  4=most function calls and data parsing messages
+	  5=highly repetitive mesgs
 
   NAME: snapshot
   TYPE: integer (Boolean)
@@ -116,24 +116,24 @@ MODULE PARAMETERS:
   TYPE: integer (1-4 for OV511, 1-31 for OV511+)
   DEFAULT: 1
   DESC: Number of cameras allowed to stream simultaneously on a single bus.
-        Values higher than 1 reduce the data rate of each camera, allowing two
-        or more to be used at once. If you have a complicated setup involving
-        both OV511 and OV511+ cameras, trial-and-error may be necessary for
-        finding the optimum setting.
+	Values higher than 1 reduce the data rate of each camera, allowing two
+	or more to be used at once. If you have a complicated setup involving
+	both OV511 and OV511+ cameras, trial-and-error may be necessary for
+	finding the optimum setting.
 
   NAME: compress
   TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: Set this to 1 to turn on the camera's compression engine. This can
-        potentially increase the frame rate at the expense of quality, if you
-        have a fast CPU. You must load the proper compression module for your
-        camera before starting your application (ov511_decomp or ov518_decomp).
+	potentially increase the frame rate at the expense of quality, if you
+	have a fast CPU. You must load the proper compression module for your
+	camera before starting your application (ov511_decomp or ov518_decomp).
 
   NAME: testpat
   TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: This configures the camera's sensor to transmit a colored test-pattern
-        instead of an image. This does not work correctly yet.
+	instead of an image. This does not work correctly yet.
 
   NAME: dumppix
   TYPE: integer (0-2)

+ 39 - 39
Documentation/video4linux/sn9c102.txt

@@ -1,9 +1,9 @@
 
-                         SN9C10x PC Camera Controllers
-                                Driver for Linux
-                         =============================
+			 SN9C10x PC Camera Controllers
+				Driver for Linux
+			 =============================
 
-                               - Documentation -
+			       - Documentation -
 
 
 Index
@@ -176,46 +176,46 @@ Name:           video_nr
 Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L2 minor mode number:
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 64 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                recognized camera and use auto for the first one and for every
-                other camera.
+		-1 = use next available
+		 n = use minor number n
+		You can specify up to 64 cameras this way.
+		For example:
+		video_nr=-1,2,-1 would assign minor number 2 to the second
+		recognized camera and use auto for the first one and for every
+		other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]>
 Description:    Force the application to unmap previously mapped buffer memory
-                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
-                all the applications support this feature. This parameter is
-                specific for each detected camera.
-                0 = do not force memory unmapping
-                1 = force memory unmapping (save memory)
+		before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+		all the applications support this feature. This parameter is
+		specific for each detected camera.
+		0 = do not force memory unmapping
+		1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           frame_timeout
 Type:           uint array (min = 0, max = 64)
 Syntax:         <n[,...]>
 Description:    Timeout for a video frame in seconds. This parameter is
-                specific for each detected camera. This parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		specific for each detected camera. This parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 3:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = more verbose messages
-                Level 3 is useful for testing only, when only one device
-                is used. It also shows some more informations about the
-                hardware being detected. This parameter can be changed at
-                runtime thanks to the /sys filesystem interface.
+		0 = none (use carefully)
+		1 = critical errors
+		2 = significant informations
+		3 = more verbose messages
+		Level 3 is useful for testing only, when only one device
+		is used. It also shows some more informations about the
+		hardware being detected. This parameter can be changed at
+		runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
@@ -280,24 +280,24 @@ Byte #  Value         Description
 0x04    0xC4          Frame synchronisation pattern.
 0x05    0x96          Frame synchronisation pattern.
 0x06    0xXX          Unknown meaning. The exact value depends on the chip;
-                      possible values are 0x00, 0x01 and 0x20.
+		      possible values are 0x00, 0x01 and 0x20.
 0x07    0xXX          Variable value, whose bits are ff00uzzc, where ff is a
-                      frame counter, u is unknown, zz is a size indicator
-                      (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
-                      "compression enabled" (1 = yes, 0 = no).
+		      frame counter, u is unknown, zz is a size indicator
+		      (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
+		      "compression enabled" (1 = yes, 0 = no).
 0x08    0xXX          Brightness sum inside Auto-Exposure area (low-byte).
 0x09    0xXX          Brightness sum inside Auto-Exposure area (high-byte).
-                      For a pure white image, this number will be equal to 500
-                      times the area of the specified AE area. For images
-                      that are not pure white, the value scales down according
-                      to relative whiteness.
+		      For a pure white image, this number will be equal to 500
+		      times the area of the specified AE area. For images
+		      that are not pure white, the value scales down according
+		      to relative whiteness.
 0x0A    0xXX          Brightness sum outside Auto-Exposure area (low-byte).
 0x0B    0xXX          Brightness sum outside Auto-Exposure area (high-byte).
-                      For a pure white image, this number will be equal to 125
-                      times the area outside of the specified AE area. For
-                      images that are not pure white, the value scales down
-                      according to relative whiteness.
-                      according to relative whiteness.
+		      For a pure white image, this number will be equal to 125
+		      times the area outside of the specified AE area. For
+		      images that are not pure white, the value scales down
+		      according to relative whiteness.
+		      according to relative whiteness.
 
 The following bytes are used by the SN9C103 bridge only:
 

+ 192 - 0
Documentation/video4linux/v4lgrab.c

@@ -0,0 +1,192 @@
+/* Simple Video4Linux image grabber. */
+/*
+ *	Video4Linux Driver Test/Example Framegrabbing Program
+ *
+ *	Compile with:
+ *		gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
+ *      Use as:
+ *              v4lgrab >image.ppm
+ *
+ *	Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>
+ *      Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c
+ *      with minor modifications (Dave Forrest, drf5n@virginia.edu).
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#include <linux/types.h>
+#include <linux/videodev.h>
+
+#define FILE "/dev/video0"
+
+/* Stole this from tvset.c */
+
+#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b)                   \
+{                                                                       \
+	switch (format)                                                 \
+	{                                                               \
+		case VIDEO_PALETTE_GREY:                                \
+			switch (depth)                                  \
+			{                                               \
+				case 4:                                 \
+				case 6:                                 \
+				case 8:                                 \
+					(r) = (g) = (b) = (*buf++ << 8);\
+					break;                          \
+									\
+				case 16:                                \
+					(r) = (g) = (b) =               \
+						*((unsigned short *) buf);      \
+					buf += 2;                       \
+					break;                          \
+			}                                               \
+			break;                                          \
+									\
+									\
+		case VIDEO_PALETTE_RGB565:                              \
+		{                                                       \
+			unsigned short tmp = *(unsigned short *)buf;    \
+			(r) = tmp&0xF800;                               \
+			(g) = (tmp<<5)&0xFC00;                          \
+			(b) = (tmp<<11)&0xF800;                         \
+			buf += 2;                                       \
+		}                                                       \
+		break;                                                  \
+									\
+		case VIDEO_PALETTE_RGB555:                              \
+			(r) = (buf[0]&0xF8)<<8;                         \
+			(g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8;    \
+			(b) = ((buf[1] << 2 ) & 0xF8)<<8;               \
+			buf += 2;                                       \
+			break;                                          \
+									\
+		case VIDEO_PALETTE_RGB24:                               \
+			(r) = buf[0] << 8; (g) = buf[1] << 8;           \
+			(b) = buf[2] << 8;                              \
+			buf += 3;                                       \
+			break;                                          \
+									\
+		default:                                                \
+			fprintf(stderr,                                 \
+				"Format %d not yet supported\n",        \
+				format);                                \
+	}                                                               \
+}
+
+int get_brightness_adj(unsigned char *image, long size, int *brightness) {
+  long i, tot = 0;
+  for (i=0;i<size*3;i++)
+    tot += image[i];
+  *brightness = (128 - tot/(size*3))/3;
+  return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
+}
+
+int main(int argc, char ** argv)
+{
+  int fd = open(FILE, O_RDONLY), f;
+  struct video_capability cap;
+  struct video_window win;
+  struct video_picture vpic;
+
+  unsigned char *buffer, *src;
+  int bpp = 24, r, g, b;
+  unsigned int i, src_depth;
+
+  if (fd < 0) {
+    perror(FILE);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
+    perror("VIDIOGCAP");
+    fprintf(stderr, "(" FILE " not a video4linux device?)\n");
+    close(fd);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
+    perror("VIDIOCGWIN");
+    close(fd);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
+    perror("VIDIOCGPICT");
+    close(fd);
+    exit(1);
+  }
+
+  if (cap.type & VID_TYPE_MONOCHROME) {
+    vpic.depth=8;
+    vpic.palette=VIDEO_PALETTE_GREY;    /* 8bit grey */
+    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+      vpic.depth=6;
+      if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+	vpic.depth=4;
+	if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+	  fprintf(stderr, "Unable to find a supported capture format.\n");
+	  close(fd);
+	  exit(1);
+	}
+      }
+    }
+  } else {
+    vpic.depth=24;
+    vpic.palette=VIDEO_PALETTE_RGB24;
+
+    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+      vpic.palette=VIDEO_PALETTE_RGB565;
+      vpic.depth=16;
+
+      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+	vpic.palette=VIDEO_PALETTE_RGB555;
+	vpic.depth=15;
+
+	if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+	  fprintf(stderr, "Unable to find a supported capture format.\n");
+	  return -1;
+	}
+      }
+    }
+  }
+
+  buffer = malloc(win.width * win.height * bpp);
+  if (!buffer) {
+    fprintf(stderr, "Out of memory.\n");
+    exit(1);
+  }
+
+  do {
+    int newbright;
+    read(fd, buffer, win.width * win.height * bpp);
+    f = get_brightness_adj(buffer, win.width * win.height, &newbright);
+    if (f) {
+      vpic.brightness += (newbright << 8);
+      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+	perror("VIDIOSPICT");
+	break;
+      }
+    }
+  } while (f);
+
+  fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
+
+  src = buffer;
+
+  for (i = 0; i < win.width * win.height; i++) {
+    READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
+    fputc(r>>8, stdout);
+    fputc(g>>8, stdout);
+    fputc(b>>8, stdout);
+  }
+
+  close(fd);
+  return 0;
+}

+ 81 - 81
Documentation/video4linux/w9968cf.txt

@@ -1,9 +1,9 @@
 
-                   W996[87]CF JPEG USB Dual Mode Camera Chip
-                     Driver for Linux 2.6 (basic version)
-                   =========================================
+		   W996[87]CF JPEG USB Dual Mode Camera Chip
+		     Driver for Linux 2.6 (basic version)
+		   =========================================
 
-                               - Documentation -
+			       - Documentation -
 
 
 Index
@@ -188,57 +188,57 @@ Name:            ovmod_load
 Type:            bool
 Syntax:          <0|1>
 Description:     Automatic 'ovcamchip' module loading: 0 disabled, 1 enabled.
-                 If enabled, 'insmod' searches for the required 'ovcamchip'
-                 module in the system, according to its configuration, and
-                 loads that module automatically. This action is performed as
-                 once soon as the 'w9968cf' module is loaded into memory.
+		 If enabled, 'insmod' searches for the required 'ovcamchip'
+		 module in the system, according to its configuration, and
+		 loads that module automatically. This action is performed as
+		 once soon as the 'w9968cf' module is loaded into memory.
 Default:         1
 Note:            The kernel must be compiled with the CONFIG_KMOD option
-                 enabled for the 'ovcamchip' module to be loaded and for
-                 this parameter to be present.
+		 enabled for the 'ovcamchip' module to be loaded and for
+		 this parameter to be present.
 -------------------------------------------------------------------------------
 Name:           simcams
 Type:           int
 Syntax:         <n>
 Description:    Number of cameras allowed to stream simultaneously.
-                n may vary from 0 to 32.
+		n may vary from 0 to 32.
 Default:        32
 -------------------------------------------------------------------------------
 Name:           video_nr
 Type:           int array (min = 0, max = 32)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L minor mode number.
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 32 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                recognized camera and use auto for the first one and for every
-                other camera.
+		-1 = use next available
+		 n = use minor number n
+		You can specify up to 32 cameras this way.
+		For example:
+		video_nr=-1,2,-1 would assign minor number 2 to the second
+		recognized camera and use auto for the first one and for every
+		other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           packet_size
 Type:           int array (min = 0, max = 32)
 Syntax:         <n[,...]>
 Description:    Specify the maximum data payload size in bytes for alternate
-                settings, for each device. n is scaled between 63 and 1023.
+		settings, for each device. n is scaled between 63 and 1023.
 Default:        1023
 -------------------------------------------------------------------------------
 Name:           max_buffers
 Type:           int array (min = 0, max = 32)
 Syntax:         <n[,...]>
 Description:    For advanced users.
-                Specify the maximum number of video frame buffers to allocate
-                for each device, from 2 to 32.
+		Specify the maximum number of video frame buffers to allocate
+		for each device, from 2 to 32.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           double_buffer
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Hardware double buffering: 0 disabled, 1 enabled.
-                It should be enabled if you want smooth video output: if you
-                obtain out of sync. video, disable it, or try to
-                decrease the 'clockdiv' module parameter value.
+		It should be enabled if you want smooth video output: if you
+		obtain out of sync. video, disable it, or try to
+		decrease the 'clockdiv' module parameter value.
 Default:        1 for every device.
 -------------------------------------------------------------------------------
 Name:           clamping
@@ -251,9 +251,9 @@ Name:           filter_type
 Type:           int array (min = 0, max = 32)
 Syntax:         <0|1|2[,...]>
 Description:    Video filter type.
-                0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
-                The filter is used to reduce noise and aliasing artifacts
-                produced by the CCD or CMOS image sensor.
+		0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
+		The filter is used to reduce noise and aliasing artifacts
+		produced by the CCD or CMOS image sensor.
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           largeview
@@ -266,9 +266,9 @@ Name:           upscaling
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Software scaling (for non-compressed video only):
-                0 disabled, 1 enabled.
-                Disable it if you have a slow CPU or you don't have enough
-                memory.
+		0 disabled, 1 enabled.
+		Disable it if you have a slow CPU or you don't have enough
+		memory.
 Default:        0 for every device.
 Note:           If 'w9968cf-vpp' is not present, this parameter is set to 0.
 -------------------------------------------------------------------------------
@@ -276,36 +276,36 @@ Name:           decompression
 Type:           int array (min = 0, max = 32)
 Syntax:         <0|1|2[,...]>
 Description:    Software video decompression:
-                0 = disables decompression
-                    (doesn't allow formats needing decompression).
-                1 = forces decompression
-                    (allows formats needing decompression only).
-                2 = allows any permitted formats.
-                Formats supporting (de)compressed video are YUV422P and
-                YUV420P/YUV420 in any resolutions where width and height are
-                multiples of 16.
+		0 = disables decompression
+		    (doesn't allow formats needing decompression).
+		1 = forces decompression
+		    (allows formats needing decompression only).
+		2 = allows any permitted formats.
+		Formats supporting (de)compressed video are YUV422P and
+		YUV420P/YUV420 in any resolutions where width and height are
+		multiples of 16.
 Default:        2 for every device.
 Note:           If 'w9968cf-vpp' is not present, forcing decompression is not
-                allowed; in this case this parameter is set to 2.
+		allowed; in this case this parameter is set to 2.
 -------------------------------------------------------------------------------
 Name:           force_palette
 Type:           int array (min = 0, max = 32)
 Syntax:         <0|9|10|13|15|8|7|1|6|3|4|5[,...]>
 Description:    Force picture palette.
-                In order:
-                 0 = Off - allows any of the following formats:
-                 9 = UYVY    16 bpp - Original video, compression disabled
-                10 = YUV420  12 bpp - Original video, compression enabled
-                13 = YUV422P 16 bpp - Original video, compression enabled
-                15 = YUV420P 12 bpp - Original video, compression enabled
-                 8 = YUVY    16 bpp - Software conversion from UYVY
-                 7 = YUV422  16 bpp - Software conversion from UYVY
-                 1 = GREY     8 bpp - Software conversion from UYVY
-                 6 = RGB555  16 bpp - Software conversion from UYVY
-                 3 = RGB565  16 bpp - Software conversion from UYVY
-                 4 = RGB24   24 bpp - Software conversion from UYVY
-                 5 = RGB32   32 bpp - Software conversion from UYVY
-                When not 0, this parameter will override 'decompression'.
+		In order:
+		 0 = Off - allows any of the following formats:
+		 9 = UYVY    16 bpp - Original video, compression disabled
+		10 = YUV420  12 bpp - Original video, compression enabled
+		13 = YUV422P 16 bpp - Original video, compression enabled
+		15 = YUV420P 12 bpp - Original video, compression enabled
+		 8 = YUVY    16 bpp - Software conversion from UYVY
+		 7 = YUV422  16 bpp - Software conversion from UYVY
+		 1 = GREY     8 bpp - Software conversion from UYVY
+		 6 = RGB555  16 bpp - Software conversion from UYVY
+		 3 = RGB565  16 bpp - Software conversion from UYVY
+		 4 = RGB24   24 bpp - Software conversion from UYVY
+		 5 = RGB32   32 bpp - Software conversion from UYVY
+		When not 0, this parameter will override 'decompression'.
 Default:        0 for every device. Initial palette is 9 (UYVY).
 Note:           If 'w9968cf-vpp' is not present, this parameter is set to 9.
 -------------------------------------------------------------------------------
@@ -313,77 +313,77 @@ Name:           force_rgb
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Read RGB video data instead of BGR:
-                1 = use RGB component ordering.
-                0 = use BGR component ordering.
-                This parameter has effect when using RGBX palettes only.
+		1 = use RGB component ordering.
+		0 = use BGR component ordering.
+		This parameter has effect when using RGBX palettes only.
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           autobright
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Image sensor automatically changes brightness:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           autoexp
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Image sensor automatically changes exposure:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        1 for every device.
 -------------------------------------------------------------------------------
 Name:           lightfreq
 Type:           int array (min = 0, max = 32)
 Syntax:         <50|60[,...]>
 Description:    Light frequency in Hz:
-                50 for European and Asian lighting, 60 for American lighting.
+		50 for European and Asian lighting, 60 for American lighting.
 Default:        50 for every device.
 -------------------------------------------------------------------------------
 Name:           bandingfilter
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Banding filter to reduce effects of fluorescent
-                lighting:
-                0 disabled, 1 enabled.
-                This filter tries to reduce the pattern of horizontal
-                light/dark bands caused by some (usually fluorescent) lighting.
+		lighting:
+		0 disabled, 1 enabled.
+		This filter tries to reduce the pattern of horizontal
+		light/dark bands caused by some (usually fluorescent) lighting.
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           clockdiv
 Type:           int array (min = 0, max = 32)
 Syntax:         <-1|n[,...]>
 Description:    Force pixel clock divisor to a specific value (for experts):
-                n may vary from 0 to 127.
-                -1 for automatic value.
-                See also the 'double_buffer' module parameter.
+		n may vary from 0 to 127.
+		-1 for automatic value.
+		See also the 'double_buffer' module parameter.
 Default:        -1 for every device.
 -------------------------------------------------------------------------------
 Name:           backlight
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Objects are lit from behind:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           mirror
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Reverse image horizontally:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           monochrome
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    The image sensor is monochrome:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           brightness
 Type:           long array (min = 0, max = 32)
 Syntax:         <n[,...]>
 Description:    Set picture brightness (0-65535).
-                This parameter has no effect if 'autobright' is enabled.
+		This parameter has no effect if 'autobright' is enabled.
 Default:        31000 for every device.
 -------------------------------------------------------------------------------
 Name:           hue
@@ -414,23 +414,23 @@ Name:           debug
 Type:           int
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 6:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = configuration or general messages
-                4 = warnings
-                5 = called functions
-                6 = function internals
-                Level 5 and 6 are useful for testing only, when only one
-                device is used.
+		0 = none (use carefully)
+		1 = critical errors
+		2 = significant informations
+		3 = configuration or general messages
+		4 = warnings
+		5 = called functions
+		6 = function internals
+		Level 5 and 6 are useful for testing only, when only one
+		device is used.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           specific_debug
 Type:           bool
 Syntax:         <0|1>
 Description:    Enable or disable specific debugging messages:
-                0 = print messages concerning every level <= 'debug' level.
-                1 = print messages concerning the level indicated by 'debug'.
+		0 = print messages concerning every level <= 'debug' level.
+		1 = print messages concerning the level indicated by 'debug'.
 Default:        0
 -------------------------------------------------------------------------------
 

+ 48 - 32
Documentation/video4linux/zc0301.txt

@@ -1,9 +1,9 @@
 
-                    ZC0301 Image Processor and Control Chip
-                                Driver for Linux
-                    =======================================
+	      ZC0301 and ZC0301P Image Processor and Control Chip
+				Driver for Linux
+	      ===================================================
 
-                               - Documentation -
+			       - Documentation -
 
 
 Index
@@ -51,13 +51,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 4. Overview and features
 ========================
-This driver supports the video interface of the devices mounting the ZC0301
-Image Processor and Control Chip.
+This driver supports the video interface of the devices mounting the ZC0301 or
+ZC0301P Image Processors and Control Chips.
 
 The driver relies on the Video4Linux2 and USB core modules. It has been
 designed to run properly on SMP systems as well.
 
-The latest version of the ZC0301 driver can be found at the following URL:
+The latest version of the ZC0301[P] driver can be found at the following URL:
 http://www.linux-projects.org/
 
 Some of the features of the driver are:
@@ -117,7 +117,7 @@ supported by the USB Audio driver thanks to the ALSA API:
 
 And finally:
 
-	# USB Multimedia devices
+	# V4L USB devices
 	#
 	CONFIG_USB_ZC0301=m
 
@@ -146,46 +146,46 @@ Name:           video_nr
 Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L2 minor mode number:
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 64 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                registered camera and use auto for the first one and for every
-                other camera.
+		-1 = use next available
+		 n = use minor number n
+		You can specify up to 64 cameras this way.
+		For example:
+		video_nr=-1,2,-1 would assign minor number 2 to the second
+		registered camera and use auto for the first one and for every
+		other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]>
 Description:    Force the application to unmap previously mapped buffer memory
-                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
-                all the applications support this feature. This parameter is
-                specific for each detected camera.
-                0 = do not force memory unmapping
-                1 = force memory unmapping (save memory)
+		before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+		all the applications support this feature. This parameter is
+		specific for each detected camera.
+		0 = do not force memory unmapping
+		1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           frame_timeout
 Type:           uint array (min = 0, max = 64)
 Syntax:         <n[,...]>
 Description:    Timeout for a video frame in seconds. This parameter is
-                specific for each detected camera. This parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		specific for each detected camera. This parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 3:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = more verbose messages
-                Level 3 is useful for testing only, when only one device
-                is used at the same time. It also shows some more informations
-                about the hardware being detected. This module parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		0 = none (use carefully)
+		1 = critical errors
+		2 = significant informations
+		3 = more verbose messages
+		Level 3 is useful for testing only, when only one device
+		is used at the same time. It also shows some more informations
+		about the hardware being detected. This module parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
@@ -204,11 +204,25 @@ Vendor ID  Product ID
 0x041e     0x4017
 0x041e     0x401c
 0x041e     0x401e
+0x041e     0x401f
+0x041e     0x4022
 0x041e     0x4034
 0x041e     0x4035
+0x041e     0x4036
+0x041e     0x403a
+0x0458     0x7007
+0x0458     0x700C
+0x0458     0x700f
+0x046d     0x08ae
+0x055f     0xd003
+0x055f     0xd004
 0x046d     0x08ae
 0x0ac8     0x0301
+0x0ac8     0x301b
+0x0ac8     0x303b
+0x10fd     0x0128
 0x10fd     0x8050
+0x10fd     0x804e
 
 The list above does not imply that all those devices work with this driver: up
 until now only the ones that mount the following image sensors are supported;
@@ -217,6 +231,7 @@ kernel messages will always tell you whether this is the case:
 Model       Manufacturer
 -----       ------------
 PAS202BCB   PixArt Imaging, Inc.
+PB-0330     Photobit Corporation
 
 
 9. Notes for V4L2 application developers
@@ -250,5 +265,6 @@ the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
   been taken from the documentation of the ZC030x Video4Linux1 driver written
   by Andrew Birkett <andy@nobugs.org>;
 - The initialization values of the ZC0301 controller connected to the PAS202BCB
-  image sensor have been taken from the SPCA5XX driver maintained by
-  Michel Xhaard <mxhaard@magic.fr>.
+  and PB-0330 image sensors have been taken from the SPCA5XX driver maintained
+  by Michel Xhaard <mxhaard@magic.fr>;
+- Stanislav Lechev donated one camera.

+ 5 - 2
drivers/media/Kconfig

@@ -25,7 +25,7 @@ config VIDEO_DEV
 	  module will be called videodev.
 
 config VIDEO_V4L1
-	boolean "Enable Video For Linux API 1 (DEPRECATED)"
+	bool "Enable Video For Linux API 1 (DEPRECATED)"
 	depends on VIDEO_DEV
 	select VIDEO_V4L1_COMPAT
 	default y
@@ -36,7 +36,7 @@ config VIDEO_V4L1
 	  If you are unsure as to whether this is required, answer Y.
 
 config VIDEO_V4L1_COMPAT
-	boolean "Enable Video For Linux API 1 compatible Layer"
+	bool "Enable Video For Linux API 1 compatible Layer"
 	depends on VIDEO_DEV
 	default y
 	---help---
@@ -82,6 +82,9 @@ config VIDEO_IR
 config VIDEO_TVEEPROM
 	tristate
 
+config VIDEO_CX2341X
+	tristate
+
 config USB_DABUSB
 	tristate "DABUSB driver"
 	depends on USB

+ 1 - 1
drivers/media/common/Makefile

@@ -1,5 +1,5 @@
 saa7146-objs    := saa7146_i2c.o saa7146_core.o
-saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
 ir-common-objs  := ir-functions.o ir-keymaps.o
 
 obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o

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

@@ -269,4 +269,3 @@ EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
  * c-basic-offset: 8
  * End:
  */
-

+ 71 - 11
drivers/media/common/ir-keymaps.c

@@ -618,7 +618,7 @@ IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
 
 EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
 
-IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
 	[ 0x3a ] = KEY_0,
 	[ 0x31 ] = KEY_1,
 	[ 0x32 ] = KEY_2,
@@ -670,7 +670,7 @@ IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
 	[ 0x27 ] = KEY_RECORD,
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
 
 IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
 	[ 0x0f ] = KEY_0,
@@ -1263,34 +1263,51 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
 	[ 0x0f ] = KEY_9,
 
 	[ 0x00 ] = KEY_POWER,
-	[ 0x02 ] = KEY_TUNER,		/* TV/FM */
-	[ 0x1e ] = KEY_VIDEO,
+	[ 0x1b ] = KEY_AUDIO,           /* Audio Source */
+	[ 0x02 ] = KEY_TUNER,		/* TV/FM, not on Y0400052 */
+	[ 0x1e ] = KEY_VIDEO,           /* Video Source */
+	[ 0x16 ] = KEY_INFO,            /* Display information */
 	[ 0x04 ] = KEY_VOLUMEUP,
 	[ 0x08 ] = KEY_VOLUMEDOWN,
 	[ 0x0c ] = KEY_CHANNELUP,
 	[ 0x10 ] = KEY_CHANNELDOWN,
 	[ 0x03 ] = KEY_ZOOM,		/* fullscreen */
-	[ 0x1f ] = KEY_SUBTITLE,		/* closed caption/teletext */
+	[ 0x1f ] = KEY_TEXT,		/* closed caption/teletext */
 	[ 0x20 ] = KEY_SLEEP,
+	[ 0x29 ] = KEY_CLEAR,           /* boss key */
 	[ 0x14 ] = KEY_MUTE,
 	[ 0x2b ] = KEY_RED,
 	[ 0x2c ] = KEY_GREEN,
 	[ 0x2d ] = KEY_YELLOW,
 	[ 0x2e ] = KEY_BLUE,
-	[ 0x18 ] = KEY_KPPLUS,		/* fine tune + */
-	[ 0x19 ] = KEY_KPMINUS,		/* fine tune - */
+	[ 0x18 ] = KEY_KPPLUS,		/* fine tune + , not on Y040052 */
+	[ 0x19 ] = KEY_KPMINUS,		/* fine tune - , not on Y040052 */
+	[ 0x2a ] = KEY_MEDIA,           /* PIP (Picture in picture */
 	[ 0x21 ] = KEY_DOT,
 	[ 0x13 ] = KEY_ENTER,
-	[ 0x22 ] = KEY_BACK,
+	[ 0x11 ] = KEY_LAST,            /* Recall (last channel */
+	[ 0x22 ] = KEY_PREVIOUS,
 	[ 0x23 ] = KEY_PLAYPAUSE,
 	[ 0x24 ] = KEY_NEXT,
+	[ 0x25 ] = KEY_ARCHIVE,       /* Time Shifting */
 	[ 0x26 ] = KEY_STOP,
-	[ 0x27 ] = KEY_RECORD
+	[ 0x27 ] = KEY_RECORD,
+	[ 0x28 ] = KEY_SAVE,          /* Screenshot */
+	[ 0x2f ] = KEY_MENU,
+	[ 0x30 ] = KEY_CANCEL,
+	[ 0x31 ] = KEY_CHANNEL,       /* Channel Surf */
+	[ 0x32 ] = KEY_SUBTITLE,
+	[ 0x33 ] = KEY_LANGUAGE,
+	[ 0x34 ] = KEY_REWIND,
+	[ 0x35 ] = KEY_FASTFORWARD,
+	[ 0x36 ] = KEY_TV,
+	[ 0x37 ] = KEY_RADIO,         /* FM */
+	[ 0x38 ] = KEY_DVD
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_winfast);
 
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE] = {
 	[ 0x59 ] = KEY_MUTE,
 	[ 0x4a ] = KEY_POWER,
 
@@ -1348,7 +1365,7 @@ IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
 	[ 0x0a ] = KEY_BACKSPACE,
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color);
 
 /* Hauppauge: the newer, gray remotes (seems there are multiple
  * slightly different versions), shipped with cx88+ivtv cards.
@@ -1413,3 +1430,46 @@ IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
 
 EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
 
+IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE] = {
+	[ 0x1d ] = KEY_SWITCHVIDEOMODE, /* switch inputs */
+	[ 0x2a ] = KEY_FRONT,
+
+	[ 0x3e ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x06 ] = KEY_3,
+	[ 0x0a ] = KEY_4,
+	[ 0x0e ] = KEY_5,
+	[ 0x12 ] = KEY_6,
+	[ 0x16 ] = KEY_7,
+	[ 0x1a ] = KEY_8,
+	[ 0x1e ] = KEY_9,
+	[ 0x3a ] = KEY_0,
+	[ 0x22 ] = KEY_NUMLOCK,         /* -/-- */
+	[ 0x20 ] = KEY_REFRESH,
+
+	[ 0x03 ] = KEY_BRIGHTNESSDOWN,
+	[ 0x28 ] = KEY_AUDIO,
+	[ 0x3c ] = KEY_UP,
+	[ 0x3f ] = KEY_LEFT,
+	[ 0x2e ] = KEY_MUTE,
+	[ 0x3b ] = KEY_RIGHT,
+	[ 0x00 ] = KEY_DOWN,
+	[ 0x07 ] = KEY_BRIGHTNESSUP,
+	[ 0x2c ] = KEY_TEXT,
+
+	[ 0x37 ] = KEY_RECORD,
+	[ 0x17 ] = KEY_PLAY,
+	[ 0x13 ] = KEY_PAUSE,
+	[ 0x26 ] = KEY_STOP,
+	[ 0x18 ] = KEY_FASTFORWARD,
+	[ 0x14 ] = KEY_REWIND,
+	[ 0x33 ] = KEY_ZOOM,
+	[ 0x32 ] = KEY_KEYBOARD,
+	[ 0x30 ] = KEY_GOTO,            /* Pointing arrow */
+	[ 0x36 ] = KEY_MACRO,           /* Maximize/Minimize (yellow) */
+	[ 0x0b ] = KEY_RADIO,
+	[ 0x10 ] = KEY_POWER,
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_npgtech);

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

@@ -501,6 +501,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_vv_init);
 
 int saa7146_vv_release(struct saa7146_dev* dev)
 {
@@ -515,6 +516,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_vv_release);
 
 int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 			    char *name, int type)
@@ -553,6 +555,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 	*vid = vfd;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_register_device);
 
 int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
 {
@@ -571,6 +574,7 @@ int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_unregister_device);
 
 static int __init saa7146_vv_init_module(void)
 {

+ 1 - 0
drivers/media/common/saa7146_hlp.c

@@ -641,6 +641,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy
 	vv->current_hps_source = source;
 	vv->current_hps_sync = sync;
 }
+EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
 
 int saa7146_enable_overlay(struct saa7146_fh *fh)
 {

+ 2 - 0
drivers/media/common/saa7146_video.c

@@ -318,6 +318,7 @@ int saa7146_start_preview(struct saa7146_fh *fh)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
 
 int saa7146_stop_preview(struct saa7146_fh *fh)
 {
@@ -352,6 +353,7 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
 
 static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
 {

+ 0 - 12
drivers/media/common/saa7146_vv_ksyms.c

@@ -1,12 +0,0 @@
-#include <linux/module.h>
-#include <media/saa7146_vv.h>
-
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
-
-EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
-EXPORT_SYMBOL_GPL(saa7146_register_device);
-EXPORT_SYMBOL_GPL(saa7146_unregister_device);
-
-EXPORT_SYMBOL_GPL(saa7146_vv_init);
-EXPORT_SYMBOL_GPL(saa7146_vv_release);

+ 73 - 49
drivers/media/dvb/b2c2/flexcop-fe-tuner.c

@@ -14,6 +14,7 @@
 #include "stv0297.h"
 #include "mt312.h"
 #include "lgdt330x.h"
+#include "lg_h06xf.h"
 #include "dvb-pll.h"
 
 /* lnb control */
@@ -166,11 +167,12 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate,
 	return 0;
 }
 
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	u8 buf[4];
 	u32 div;
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	struct flexcop_device *fc = fe->dvb->priv;
 
 	div = params->frequency / 125;
 
@@ -181,8 +183,11 @@ static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter
 
 	if (params->frequency < 1500000) buf[3] |= 0x10;
 
-	if (i2c_transfer(i2c, &msg, 1) != 1)
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
 		return -EIO;
+	}
 	return 0;
 }
 
@@ -241,7 +246,6 @@ static struct stv0299_config samsung_tbmu24112_config = {
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 100,
 	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
-	.pll_set = samsung_tbmu24112_pll_set,
 };
 
 /* dvb-t mt352 */
@@ -264,11 +268,14 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
 	return 0;
 }
 
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
 {
 	u32 div;
 	unsigned char bs = 0;
 
+	if (buf_len < 5)
+		return -EINVAL;
+
 	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
 	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
@@ -276,19 +283,18 @@ static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_front
 	if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
 	if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
 
-	pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
+	pllbuf[0] = 0x61;
 	pllbuf[1] = div >> 8;
 	pllbuf[2] = div & 0xff;
 	pllbuf[3] = 0xcc;
 	pllbuf[4] = bs;
 
-	return 0;
+	return 5;
 }
 
 static struct mt352_config samsung_tdtc9251dh0_config = {
 	.demod_address = 0x0f,
 	.demod_init    = samsung_tdtc9251dh0_demod_init,
-	.pll_set       = samsung_tdtc9251dh0_pll_set,
 };
 
 static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
@@ -297,56 +303,21 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
 	return request_firmware(fw, name, fc->dev);
 }
 
-static int lgdt3303_pll_set(struct dvb_frontend* fe,
-			    struct dvb_frontend_parameters* params)
+static int lgdt3303_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	struct flexcop_device *fc = fe->dvb->priv;
-	u8 buf[4];
-	struct i2c_msg msg =
-		{ .addr = 0x61, .flags = 0, .buf = buf, .len = 4 };
-	int err;
-
-	dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0);
-	dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
-			__FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
-	if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
-		printk(KERN_WARNING "lgdt3303: %s error "
-			   "(addr %02x <- %02x, err = %i)\n",
-			   __FUNCTION__, buf[0], buf[1], err);
-		if (err < 0)
-			return err;
-		else
-			return -EREMOTEIO;
-	}
-
-	buf[0] = 0x86 | 0x18;
-	buf[1] = 0x50;
-	msg.len = 2;
-	if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
-		printk(KERN_WARNING "lgdt3303: %s error "
-			   "(addr %02x <- %02x, err = %i)\n",
-			   __FUNCTION__, buf[0], buf[1], err);
-		if (err < 0)
-			return err;
-		else
-			return -EREMOTEIO;
-	}
-
-	return 0;
+	return lg_h06xf_pll_set(fe, &fc->i2c_adap, params);
 }
 
 static struct lgdt330x_config air2pc_atsc_hd5000_config = {
 	.demod_address       = 0x59,
 	.demod_chip          = LGDT3303,
 	.serial_mpeg         = 0x04,
-	.pll_set             = lgdt3303_pll_set,
 	.clock_polarity_flip = 1,
 };
 
 static struct nxt200x_config samsung_tbmv_config = {
 	.demod_address    = 0x0a,
-	.pll_address      = 0xc2,
-	.pll_desc         = &dvb_pll_samsung_tbmv,
 };
 
 static struct bcm3510_config air2pc_atsc_first_gen_config = {
@@ -354,7 +325,7 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = {
 	.request_firmware = flexcop_fe_request_firmware,
 };
 
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	u8 buf[4];
 	u32 div;
@@ -371,6 +342,8 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d
 	if (params->frequency < 1550000)
 		buf[3] |= 0x02;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -379,9 +352,52 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d
 static struct mt312_config skystar23_samsung_tbdu18132_config = {
 
 	.demod_address = 0x0e,
-	.pll_set = skystar23_samsung_tbdu18132_pll_set,
 };
 
+static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
+					       struct dvb_frontend_parameters *fep)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	u8 buf[4];
+	u16 div;
+	int ret;
+
+/*  62.5 kHz * 10 */
+#define REF_FREQ    625
+#define FREQ_OFFSET 36125
+
+	div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10)  / REF_FREQ; // 4 MHz = 4000 KHz
+
+	buf[0] = (u8)( div >> 8) & 0x7f;
+	buf[1] = (u8)        div & 0xff;
+
+/* F(osc) = N * Reference Freq. (62.5 kHz)
+ * byte 2 :  0 N14 N13 N12 N11 N10 N9  N8
+ * byte 3 : N7 N6  N5  N4  N3  N2  N1  N0
+ * byte 4 : 1  *   *   AGD R3  R2  R1  R0
+ * byte 5 : C1 *   RE  RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
+	buf[2] = 0x95;
+
+// Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
+//  47 - 153   0  *  0   0   0   0   0   1   0x01
+// 153 - 430   0  *  0   0   0   0   1   0   0x02
+// 430 - 822   0  *  0   0   1   0   0   0   0x08
+// 822 - 862   1  *  0   0   1   0   0   0   0x88
+
+	     if (fep->frequency <= 153000000) buf[3] = 0x01;
+	else if (fep->frequency <= 430000000) buf[3] = 0x02;
+	else if (fep->frequency <= 822000000) buf[3] = 0x08;
+	else buf[3] = 0x88;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
+	ret = fc->i2c_request(fc,FC_WRITE,FC_I2C_PORT_TUNER,0x61,buf[0],&buf[1],3);
+	deb_tuner("tuner write returned: %d\n",ret);
+
+	return 0;
+}
 
 static u8 alps_tdee4_stv0297_inittab[] = {
 	0x80, 0x01,
@@ -490,7 +506,9 @@ int flexcop_frontend_init(struct flexcop_device *fc)
 
 	/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
 	if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
-		ops = fc->fe->ops;
+		ops = &fc->fe->ops;
+
+		ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
 
 		ops->set_voltage = flexcop_set_voltage;
 
@@ -503,16 +521,19 @@ int flexcop_frontend_init(struct flexcop_device *fc)
 	/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
 	if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
 		fc->dev_type          = FC_AIR_DVB;
+		fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
 		info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
 	} else
 	/* try the air atsc 2nd generation (nxt2002) */
 	if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC2;
+		dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv);
 		info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
 	} else
 	/* try the air atsc 3nd generation (lgdt3303) */
 	if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC3;
+		fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
 		info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
 	} else
 	/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
@@ -523,11 +544,14 @@ int flexcop_frontend_init(struct flexcop_device *fc)
 	/* try the cable dvb (stv0297) */
 	if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type                        = FC_CABLE;
+		fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
 		info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
 	} else
 	/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
 	if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
-		ops = fc->fe->ops;
+		ops = &fc->fe->ops;
+
+		ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
 
 		ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
 		ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
@@ -547,7 +571,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
 	} else {
 		if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
 			err("frontend registration failed!");
-			ops = fc->fe->ops;
+			ops = &fc->fe->ops;
 			if (ops->release != NULL)
 				ops->release(fc->fe);
 			fc->fe = NULL;

+ 7 - 12
drivers/media/dvb/b2c2/flexcop-pci.c

@@ -242,19 +242,16 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
 	if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
 		return ret;
 
-	if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0)
-		goto dma1_free;
+	if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) {
+		flexcop_dma_free(&fc_pci->dma[0]);
+		return ret;
+	}
 
 	flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
 	flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO   | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
 
 	fc_pci->init_state |= FC_PCI_DMA_INIT;
 
-	goto success;
-dma1_free:
-	flexcop_dma_free(&fc_pci->dma[0]);
-
-success:
 	return ret;
 }
 
@@ -303,7 +300,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
 	spin_lock_init(&fc_pci->irq_lock);
 
 	fc_pci->init_state |= FC_PCI_INIT;
-	goto success;
+	return ret;
 
 err_pci_iounmap:
 	pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
@@ -312,8 +309,6 @@ err_pci_release_regions:
 	pci_release_regions(fc_pci->pdev);
 err_pci_disable_device:
 	pci_disable_device(fc_pci->pdev);
-
-success:
 	return ret;
 }
 
@@ -378,14 +373,14 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
 	INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
 
-	goto success;
+	return ret;
+
 err_fc_exit:
 	flexcop_device_exit(fc);
 err_pci_exit:
 	flexcop_pci_exit(fc_pci);
 err_kfree:
 	flexcop_device_kfree(fc);
-success:
 	return ret;
 }
 

+ 4 - 6
drivers/media/dvb/b2c2/flexcop-usb.c

@@ -433,11 +433,10 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
 	flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
 	flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
 
-	ret = 0;
-	goto success;
+	return 0;
+
 urb_error:
 	flexcop_usb_transfer_exit(fc_usb);
-success:
 	return ret;
 }
 
@@ -515,15 +514,14 @@ static int flexcop_usb_probe(struct usb_interface *intf,
 		goto err_fc_exit;
 
 	info("%s successfully initialized and connected.",DRIVER_NAME);
-	ret = 0;
-	goto success;
+	return 0;
+
 err_fc_exit:
 	flexcop_device_exit(fc);
 err_usb_exit:
 	flexcop_usb_exit(fc_usb);
 err_kfree:
 	flexcop_device_kfree(fc);
-success:
 	return ret;
 }
 

+ 4 - 8
drivers/media/dvb/b2c2/flexcop.c

@@ -67,7 +67,7 @@ static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 static int flexcop_dvb_init(struct flexcop_device *fc)
 {
 	int ret;
-	if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner)) < 0) {
+	if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner,fc->dev)) < 0) {
 		err("error registering DVB adapter");
 		return ret;
 	}
@@ -116,7 +116,7 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
 	dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
 
 	fc->init_state |= FC_STATE_DVB_INIT;
-	goto success;
+	return 0;
 
 err_connect_frontend:
 	fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
@@ -129,9 +129,6 @@ err_dmx_dev:
 err_dmx:
 	dvb_unregister_adapter(&fc->dvb_adapter);
 	return ret;
-
-success:
-	return 0;
 }
 
 static void flexcop_dvb_exit(struct flexcop_device *fc)
@@ -279,11 +276,10 @@ int flexcop_device_initialize(struct flexcop_device *fc)
 
 	flexcop_device_name(fc,"initialization of","complete");
 
-	ret = 0;
-	goto success;
+	return 0;
+
 error:
 	flexcop_device_exit(fc);
-success:
 	return ret;
 }
 EXPORT_SYMBOL(flexcop_device_initialize);

+ 8 - 3
drivers/media/dvb/bt8xx/bt878.c

@@ -63,8 +63,6 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
 int bt878_num;
 struct bt878 bt878[BT878_MAX];
 
-EXPORT_SYMBOL(bt878_debug);
-EXPORT_SYMBOL(bt878_verbose);
 EXPORT_SYMBOL(bt878_num);
 EXPORT_SYMBOL(bt878);
 
@@ -393,7 +391,9 @@ static struct cards card_list[] __devinitdata = {
 	{ 0x07711461, BTTV_BOARD_AVDVBT_771,			"AVermedia AverTV DVB-T 771" },
 	{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,		"DViCO FusionHDTV DVB-T Lite" },
 	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,	"DViCO FusionHDTV 5 Lite" },
-	{ 0x20007063, BTTV_BOARD_PC_HDTV,			"pcHDTV HD-2000 TV"},
+	{ 0x20007063, BTTV_BOARD_PC_HDTV,			"pcHDTV HD-2000 TV" },
+	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,			"DNTV Live! Mini" },
+
 	{ 0, -1, NULL }
 };
 
@@ -417,6 +417,11 @@ static int __devinit bt878_probe(struct pci_dev *dev,
 
 	printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
 	       bt878_num);
+	if (bt878_num >= BT878_MAX) {
+		printk(KERN_ERR "bt878: Too many devices inserted\n");
+		result = -ENOMEM;
+		goto fail0;
+	}
 	if (pci_enable_device(dev))
 		return -EIO;
 

+ 477 - 129
drivers/media/dvb/bt8xx/dst.c

@@ -38,6 +38,10 @@ static unsigned int dst_addons;
 module_param(dst_addons, int, 0644);
 MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
 
+static unsigned int dst_algo;
+module_param(dst_algo, int, 0644);
+MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
+
 #define HAS_LOCK		1
 #define ATTEMPT_TUNE		2
 #define HAS_POWER		4
@@ -47,20 +51,24 @@ MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
 #define DST_INFO		2
 #define DST_DEBUG		3
 
-#define dprintk(x, y, z, format, arg...) do {						\
-	if (z) {									\
-		if	((x > DST_ERROR) && (x > y))					\
-			printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg);	\
-		else if	((x > DST_NOTICE) && (x > y))					\
-			printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg);	\
-		else if ((x > DST_INFO) && (x > y))					\
-			printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg);	\
-		else if ((x > DST_DEBUG) && (x > y))					\
-			printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg);	\
-	} else {									\
-		if (x > y)								\
-			printk(format, ##arg);						\
-	}										\
+#define dprintk(x, y, z, format, arg...) do {				\
+	if (z) {							\
+		if	((x > DST_ERROR) && (x > y))			\
+			printk(KERN_ERR "dst(%d) %s: " format "\n",	\
+				state->bt->nr, __func__ , ##arg);	\
+		else if	((x > DST_NOTICE) && (x > y))			\
+			printk(KERN_NOTICE "dst(%d) %s: " format "\n",  \
+				state->bt->nr, __func__ , ##arg);	\
+		else if ((x > DST_INFO) && (x > y))			\
+			printk(KERN_INFO "dst(%d) %s: " format "\n",	\
+				state->bt->nr, __func__ , ##arg);	\
+		else if ((x > DST_DEBUG) && (x > y))			\
+			printk(KERN_DEBUG "dst(%d) %s: " format "\n",	\
+				state->bt->nr,  __func__ , ##arg);	\
+	} else {							\
+		if (x > y)						\
+			printk(format, ##arg);				\
+	}								\
 } while(0)
 
 
@@ -110,7 +118,7 @@ int dst_gpio_inb(struct dst_state *state, u8 *result)
 
 	*result = 0;
 	if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err);
+		dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err);
 		return -EREMOTEIO;
 	}
 	*result = (u8) rd_packet.rd.value;
@@ -363,6 +371,17 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
 		state->tx_tuna[2] = (freq >> 16) & 0xff;
 		state->tx_tuna[3] = (freq >> 8) & 0xff;
 		state->tx_tuna[4] = (u8) freq;
+	} else if (state->dst_type == DST_TYPE_IS_ATSC) {
+		freq = freq / 1000;
+		if (freq < 51000 || freq > 858000)
+			return -EINVAL;
+		state->tx_tuna[2] = (freq >> 16) & 0xff;
+		state->tx_tuna[3] = (freq >>  8) & 0xff;
+		state->tx_tuna[4] = (u8) freq;
+		state->tx_tuna[5] = 0x00;		/*	ATSC	*/
+		state->tx_tuna[6] = 0x00;
+		if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG)
+			state->tx_tuna[7] = 0x00;	/*	Digital	*/
 	} else
 		return -EINVAL;
 
@@ -447,29 +466,41 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate)
 	}
 	dprintk(verbose, DST_INFO, 1, "set symrate %u", srate);
 	srate /= 1000;
-	if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
-		sval = srate;
-		sval <<= 20;
-		do_div(sval, 88000);
-		symcalc = (u32) sval;
-		dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
-		state->tx_tuna[5] = (u8) (symcalc >> 12);
-		state->tx_tuna[6] = (u8) (symcalc >> 4);
-		state->tx_tuna[7] = (u8) (symcalc << 4);
-	} else {
-		state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
-		state->tx_tuna[6] = (u8) (srate >> 8);
-		state->tx_tuna[7] = (u8) srate;
-	}
-	state->tx_tuna[8] &= ~0x20;
-	if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
-		if (srate > 8000)
-			state->tx_tuna[8] |= 0x20;
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+			sval = srate;
+			sval <<= 20;
+			do_div(sval, 88000);
+			symcalc = (u32) sval;
+			dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
+			state->tx_tuna[5] = (u8) (symcalc >> 12);
+			state->tx_tuna[6] = (u8) (symcalc >> 4);
+			state->tx_tuna[7] = (u8) (symcalc << 4);
+		} else {
+			state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
+			state->tx_tuna[6] = (u8) (srate >> 8);
+			state->tx_tuna[7] = (u8) srate;
+		}
+		state->tx_tuna[8] &= ~0x20;
+		if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+			if (srate > 8000)
+				state->tx_tuna[8] |= 0x20;
+		}
+	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
+		dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name);
+		if (!strncmp(state->fw_name, "DCTNEW", 6)) {
+			state->tx_tuna[5] = (u8) (srate >> 8);
+			state->tx_tuna[6] = (u8) srate;
+			state->tx_tuna[7] = 0x00;
+		} else if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+			state->tx_tuna[5] = 0x00;
+			state->tx_tuna[6] = (u8) (srate >> 8);
+			state->tx_tuna[7] = (u8) srate;
+		}
 	}
 	return 0;
 }
 
-
 static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
 {
 	if (state->dst_type != DST_TYPE_IS_CABLE)
@@ -490,7 +521,10 @@ static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulatio
 		state->tx_tuna[8] = 0x80;
 		break;
 	case QAM_256:
-		state->tx_tuna[8] = 0x00;
+		if (!strncmp(state->fw_name, "DCTNEW", 6))
+			state->tx_tuna[8] = 0xff;
+		else if (!strncmp(state->fw_name, "DCT-CI", 6))
+			state->tx_tuna[8] = 0x00;
 		break;
 	case QPSK:
 	case QAM_AUTO:
@@ -523,13 +557,19 @@ u8 dst_check_sum(u8 *buf, u32 len)
 }
 EXPORT_SYMBOL(dst_check_sum);
 
-static void dst_type_flags_print(u32 type_flags)
+static void dst_type_flags_print(struct dst_state *state)
 {
+	u32 type_flags = state->type_flags;
+
 	dprintk(verbose, DST_ERROR, 0, "DST type flags :");
-	if (type_flags & DST_TYPE_HAS_NEWTUNE)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
+	if (type_flags & DST_TYPE_HAS_TS188)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188);
+	if (type_flags & DST_TYPE_HAS_NEWTUNE_2)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2);
 	if (type_flags & DST_TYPE_HAS_TS204)
 		dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204);
+	if (type_flags & DST_TYPE_HAS_VLF)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF);
 	if (type_flags & DST_TYPE_HAS_SYMDIV)
 		dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
 	if (type_flags & DST_TYPE_HAS_FW_1)
@@ -542,7 +582,7 @@ static void dst_type_flags_print(u32 type_flags)
 }
 
 
-static int dst_type_print(u8 type)
+static int dst_type_print(struct dst_state *state, u8 type)
 {
 	char *otype;
 	switch (type) {
@@ -558,6 +598,10 @@ static int dst_type_print(u8 type)
 		otype = "cable";
 		break;
 
+	case DST_TYPE_IS_ATSC:
+		otype = "atsc";
+		break;
+
 	default:
 		dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type);
 		return -EINVAL;
@@ -567,6 +611,127 @@ static int dst_type_print(u8 type)
 	return 0;
 }
 
+struct tuner_types tuner_list[] = {
+	{
+		.tuner_type = TUNER_TYPE_L64724,
+		.tuner_name = "L 64724",
+		.board_name = "UNKNOWN",
+		.fw_name    = "UNKNOWN"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1020",
+		.fw_name    = "DST-MOT"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1020",
+		.fw_name    = "DST-03T"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_MB86A15,
+		.tuner_name = "MB 86A15",
+		.board_name = "VP1022",
+		.fw_name    = "DST-03T"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_MB86A15,
+		.tuner_name = "MB 86A15",
+		.board_name = "VP1025",
+		.fw_name    = "DST-03T"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1030",
+		.fw_name    = "DST-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1030",
+		.fw_name    = "DSTMCI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2021",
+		.fw_name    = "DCTNEW"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2030",
+		.fw_name    = "DCT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2031",
+		.fw_name    = "DCT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2040",
+		.fw_name    = "DCT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP3020",
+		.fw_name    = "DTTFTA"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP3021",
+		.fw_name    = "DTTFTA"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_TDA10046,
+		.tuner_name = "TDA10046",
+		.board_name = "VP3040",
+		.fw_name    = "DTT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP3051",
+		.fw_name    = "DTTNXT"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_NXT200x,
+		.tuner_name = "NXT200x",
+		.board_name = "VP3220",
+		.fw_name    = "ATSCDI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_NXT200x,
+		.tuner_name = "NXT200x",
+		.board_name = "VP3250",
+		.fw_name    = "ATSCAD"
+	},
+};
+
 /*
 	Known cards list
 	Satellite
@@ -608,7 +773,8 @@ static struct dst_types dst_tlist[] = {
 		.offset = 0,
 		.dst_type =  DST_TYPE_IS_SAT,
 		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/*	obsolete	*/
 
 	{
@@ -616,15 +782,17 @@ static struct dst_types dst_tlist[] = {
 		.offset = 0,
 		.dst_type =  DST_TYPE_IS_SAT,
 		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/*	obsolete	*/
 
 	{
 		.device_id = "DST-030",
 		.offset =  0,
 		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/*	obsolete	*/
 
 	{
@@ -633,7 +801,8 @@ static struct dst_types dst_tlist[] = {
 		.dst_type = DST_TYPE_IS_SAT,
 		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
 		.dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
-							 | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO
+							 | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO,
+		.tuner_type = TUNER_TYPE_MULTI
 	 },
 
 	{
@@ -641,57 +810,63 @@ static struct dst_types dst_tlist[] = {
 		.offset =  0,
 		.dst_type = DST_TYPE_IS_SAT,
 		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/*	obsolete	*/
 
 	{
 		.device_id = "DST-CI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
-		.dst_feature = DST_TYPE_HAS_CA
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1,
+		.dst_feature = DST_TYPE_HAS_CA,
+		.tuner_type = 0
 	},	/*	An OEM board	*/
 
 	{
 		.device_id = "DSTMCI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT,
+		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF,
 		.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
-							| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
+							| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC,
+		.tuner_type = TUNER_TYPE_MULTI
 	},
 
 	{
 		.device_id = "DSTFCI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0
+		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/* unknown to vendor	*/
 
 	{
 		.device_id = "DCT-CI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_CABLE,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1
-							| DST_TYPE_HAS_FW_2,
-		.dst_feature = DST_TYPE_HAS_CA
+		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1	| DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF,
+		.dst_feature = DST_TYPE_HAS_CA,
+		.tuner_type = 0
 	},
 
 	{
 		.device_id = "DCTNEW",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_CABLE,
-		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD,
-		.dst_feature = 0
+		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE,
+		.dst_feature = 0,
+		.tuner_type = 0
 	},
 
 	{
 		.device_id = "DTT-CI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_TERR,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE,
-		.dst_feature = DST_TYPE_HAS_CA
+		.type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF,
+		.dst_feature = DST_TYPE_HAS_CA,
+		.tuner_type = 0
 	},
 
 	{
@@ -699,7 +874,8 @@ static struct dst_types dst_tlist[] = {
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_TERR,
 		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},
 
 	{
@@ -707,7 +883,8 @@ static struct dst_types dst_tlist[] = {
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_TERR,
 		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = DST_TYPE_HAS_ANALOG
+		.dst_feature = DST_TYPE_HAS_ANALOG,
+		.tuner_type = 0
 	},
 
 	{
@@ -715,15 +892,17 @@ static struct dst_types dst_tlist[] = {
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_ATSC,
 		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},
 
 	{
 		.device_id = "ATSCAD",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_ATSC,
-		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = 0
+		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+		.dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG,
+		.tuner_type = 0
 	},
 
 	{ }
@@ -768,6 +947,9 @@ static int dst_fw_ver(struct dst_state *state)
 
 static int dst_card_type(struct dst_state *state)
 {
+	int j;
+	struct tuner_types *p_tuner_list = NULL;
+
 	u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 	get_type[7] = dst_check_sum(get_type, 7);
 	if (dst_command(state, get_type, 8) < 0) {
@@ -775,9 +957,17 @@ static int dst_card_type(struct dst_state *state)
 		return -1;
 	}
 	memset(&state->card_info, '\0', 8);
-	memcpy(&state->card_info, &state->rxbuffer, 8);
+	memcpy(&state->card_info, &state->rxbuffer, 7);
 	dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]);
 
+	for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+		if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) {
+			state->tuner_type = p_tuner_list->tuner_type;
+			dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]",
+				p_tuner_list->tuner_name, p_tuner_list->tuner_type);
+		}
+	}
+
 	return 0;
 }
 
@@ -790,12 +980,64 @@ static int dst_get_vendor(struct dst_state *state)
 		return -1;
 	}
 	memset(&state->vendor, '\0', 8);
-	memcpy(&state->vendor, &state->rxbuffer, 8);
+	memcpy(&state->vendor, &state->rxbuffer, 7);
 	dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]);
 
 	return 0;
 }
 
+static void debug_dst_buffer(struct dst_state *state)
+{
+	int i;
+
+	if (verbose > 2) {
+		printk("%s: [", __func__);
+		for (i = 0; i < 8; i++)
+			printk(" %02x", state->rxbuffer[i]);
+		printk("]\n");
+	}
+}
+
+static int dst_check_stv0299(struct dst_state *state)
+{
+	u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	check_stv0299[7] = dst_check_sum(check_stv0299, 7);
+	if (dst_command(state, check_stv0299, 8) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed");
+		return -1;
+	}
+	debug_dst_buffer(state);
+
+	if (memcmp(&check_stv0299, &state->rxbuffer, 8)) {
+		dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM");
+		state->tuner_type = TUNER_TYPE_STV0299;
+		return 0;
+	}
+
+	return -1;
+}
+
+static int dst_check_mb86a15(struct dst_state *state)
+{
+	u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	check_mb86a15[7] = dst_check_sum(check_mb86a15, 7);
+	if (dst_command(state, check_mb86a15, 8) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed");
+		return -1;
+	}
+	debug_dst_buffer(state);
+
+	if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM");
+		state->tuner_type = TUNER_TYPE_MB86A15;
+		return 0;
+	}
+
+	return -1;
+}
+
 static int dst_get_tuner_info(struct dst_state *state)
 {
 	u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -803,60 +1045,59 @@ static int dst_get_tuner_info(struct dst_state *state)
 
 	get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
 	get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+	dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE");
 	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
-		if (dst_command(state, get_tuner_2, 8) < 0) {
-			dprintk(verbose, DST_INFO, 1, "Unsupported Command");
-			return -1;
+		if (dst_command(state, get_tuner_1, 8) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported");
+			goto force;
 		}
 	} else {
-		if (dst_command(state, get_tuner_1, 8) < 0) {
-			dprintk(verbose, DST_INFO, 1, "Unsupported Command");
-			return -1;
+		if (dst_command(state, get_tuner_2, 8) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported");
+			goto force;
 		}
 	}
 	memset(&state->board_info, '\0', 8);
 	memcpy(&state->board_info, &state->rxbuffer, 8);
 	if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
-		if (state->board_info[1] == 0x0b) {
-			if (state->type_flags & DST_TYPE_HAS_TS204)
-				state->type_flags &= ~DST_TYPE_HAS_TS204;
-			state->type_flags |= DST_TYPE_HAS_NEWTUNE;
-			dprintk(verbose, DST_INFO, 1, "DST type has TS=188");
-		} else {
-			if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
-				state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
-			state->type_flags |= DST_TYPE_HAS_TS204;
-			dprintk(verbose, DST_INFO, 1, "DST type has TS=204");
-		}
-	} else {
-		if (state->board_info[0] == 0xbc) {
-			if (state->type_flags & DST_TYPE_HAS_TS204)
-				state->type_flags &= ~DST_TYPE_HAS_TS204;
-			state->type_flags |= DST_TYPE_HAS_NEWTUNE;
-			dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]);
-
-		} else if (state->board_info[0] == 0xcc) {
-			if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
-				state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
-			state->type_flags |= DST_TYPE_HAS_TS204;
-			dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]);
+		dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
+	}
+	if (state->board_info[0] == 0xbc) {
+		if (state->type_flags != DST_TYPE_IS_ATSC)
+			state->type_flags |= DST_TYPE_HAS_TS188;
+		else
+			state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
+
+		if (state->board_info[1] == 0x01) {
+			state->dst_hw_cap |= DST_TYPE_HAS_DBOARD;
+			dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard");
 		}
 	}
 
 	return 0;
+force:
+	if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+		state->type_flags |= DST_TYPE_HAS_TS204;
+		dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name);
+	}
+
+	return -1;
 }
 
 static int dst_get_device_id(struct dst_state *state)
 {
 	u8 reply;
 
-	int i;
-	struct dst_types *p_dst_type;
+	int i, j;
+	struct dst_types *p_dst_type = NULL;
+	struct tuner_types *p_tuner_list = NULL;
+
 	u8 use_dst_type = 0;
 	u32 use_type_flags = 0;
 
 	static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
 
+	state->tuner_type = 0;
 	device_type[7] = dst_check_sum(device_type, 7);
 
 	if (write_dst(state, device_type, FIXED_COMM))
@@ -888,8 +1129,34 @@ static int dst_get_device_id(struct dst_state *state)
 
 			/*	Card capabilities	*/
 			state->dst_hw_cap = p_dst_type->dst_feature;
-			dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id);
-
+			dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id);
+			strncpy(&state->fw_name[0], p_dst_type->device_id, 6);
+			/*	Multiple tuners		*/
+			if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) {
+				switch (use_dst_type) {
+				case DST_TYPE_IS_SAT:
+					/*	STV0299 check	*/
+					if (dst_check_stv0299(state) < 0) {
+						dprintk(verbose, DST_ERROR, 1, "Unsupported");
+						state->tuner_type = TUNER_TYPE_MB86A15;
+					}
+					break;
+				default:
+					break;
+				}
+				if (dst_check_mb86a15(state) < 0)
+					dprintk(verbose, DST_ERROR, 1, "Unsupported");
+			/*	Single tuner		*/
+			} else {
+				state->tuner_type = p_dst_type->tuner_type;
+			}
+			for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+				if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) &&
+					p_tuner_list->tuner_type == state->tuner_type) {
+					dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]",
+						p_dst_type->device_id, p_tuner_list->tuner_name);
+				}
+			}
 			break;
 		}
 	}
@@ -900,10 +1167,10 @@ static int dst_get_device_id(struct dst_state *state)
 		use_dst_type = DST_TYPE_IS_SAT;
 		use_type_flags = DST_TYPE_HAS_SYMDIV;
 	}
-	dst_type_print(use_dst_type);
+	dst_type_print(state, use_dst_type);
 	state->type_flags = use_type_flags;
 	state->dst_type = use_dst_type;
-	dst_type_flags_print(state->type_flags);
+	dst_type_flags_print(state);
 
 	return 0;
 }
@@ -911,15 +1178,15 @@ static int dst_get_device_id(struct dst_state *state)
 static int dst_probe(struct dst_state *state)
 {
 	mutex_init(&state->dst_mutex);
-	if ((rdc_8820_reset(state)) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
-		return -1;
-	}
-	if (dst_addons & DST_TYPE_HAS_CA)
+	if (dst_addons & DST_TYPE_HAS_CA) {
+		if ((rdc_8820_reset(state)) < 0) {
+			dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
+			return -1;
+		}
 		msleep(4000);
-	else
+	} else {
 		msleep(100);
-
+	}
 	if ((dst_comm_init(state)) < 0) {
 		dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed.");
 		return -1;
@@ -931,7 +1198,6 @@ static int dst_probe(struct dst_state *state)
 	}
 	if (dst_get_mac(state) < 0) {
 		dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command");
-		return 0;
 	}
 	if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
 		if (dst_get_tuner_info(state) < 0)
@@ -1048,6 +1314,10 @@ static int dst_get_signal(struct dst_state *state)
 			state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
 			state->decode_strength = state->rxbuffer[4] << 8;
 			state->decode_snr = state->rxbuffer[3] << 8;
+		} else if (state->dst_type == DST_TYPE_IS_ATSC) {
+			state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0;
+			state->decode_strength = state->rxbuffer[4] << 8;
+			state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
 		}
 		state->cur_jiff = jiffies;
 	}
@@ -1078,8 +1348,9 @@ static int dst_get_tuna(struct dst_state *state)
 	state->diseq_flags &= ~(HAS_LOCK);
 	if (!dst_wait_dst_ready(state, NO_DELAY))
 		return -EIO;
-	if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
-		/* how to get variable length reply ???? */
+	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+		!(state->dst_type == DST_TYPE_IS_ATSC))
+
 		retval = read_dst(state, state->rx_tuna, 10);
 	else
 		retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
@@ -1087,7 +1358,10 @@ static int dst_get_tuna(struct dst_state *state)
 		dprintk(verbose, DST_DEBUG, 1, "read not successful");
 		return retval;
 	}
-	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+		!(state->dst_type == DST_TYPE_IS_CABLE) &&
+		!(state->dst_type == DST_TYPE_IS_ATSC)) {
+
 		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
 			dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
 			return -EIO;
@@ -1133,7 +1407,10 @@ static int dst_write_tuna(struct dvb_frontend *fe)
 		dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
 		goto error;
 	}
-	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+//	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+		(!(state->dst_type == DST_TYPE_IS_ATSC))) {
+
 		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
 		retval = write_dst(state, &state->tx_tuna[0], 10);
 	} else {
@@ -1189,9 +1466,12 @@ static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd
 
 	if (state->dst_type != DST_TYPE_IS_SAT)
 		return 0;
-	if (cmd->msg_len == 0 || cmd->msg_len > 4)
+	if (cmd->msg_len > 0 && cmd->msg_len < 5)
+		memcpy(&paket[3], cmd->msg, cmd->msg_len);
+	else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5)
+		memcpy(&paket[2], cmd->msg, cmd->msg_len);
+	else
 		return -EINVAL;
-	memcpy(&paket[3], cmd->msg, cmd->msg_len);
 	paket[7] = dst_check_sum(&paket[0], 7);
 	dst_command(state, paket, 8);
 	return 0;
@@ -1287,8 +1567,9 @@ static int dst_init(struct dvb_frontend *fe)
 	static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 };
 	static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
 	static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
-	static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
 	static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+	static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+	static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
 
 	state->inversion = INVERSION_OFF;
 	state->voltage = SEC_VOLTAGE_13;
@@ -1298,11 +1579,13 @@ static int dst_init(struct dvb_frontend *fe)
 	state->bandwidth = BANDWIDTH_7_MHZ;
 	state->cur_jiff = jiffies;
 	if (state->dst_type == DST_TYPE_IS_SAT)
-		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
 	else if (state->dst_type == DST_TYPE_IS_TERR)
-		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
 	else if (state->dst_type == DST_TYPE_IS_CABLE)
-		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+	else if (state->dst_type == DST_TYPE_IS_ATSC)
+		memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner));
 
 	return 0;
 }
@@ -1341,7 +1624,36 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
 	return 0;
 }
 
-static int dst_set_frontend(struct dvb_frontend* fe,
+static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+	struct dst_state *state = fe->demodulator_priv;
+
+	if (p != NULL) {
+		dst_set_freq(state, p->frequency);
+		dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+
+		if (state->dst_type == DST_TYPE_IS_SAT) {
+			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+				dst_set_inversion(state, p->inversion);
+			dst_set_fec(state, p->u.qpsk.fec_inner);
+			dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+			dst_set_polarization(state);
+			dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+
+		} else if (state->dst_type == DST_TYPE_IS_TERR)
+			dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+		else if (state->dst_type == DST_TYPE_IS_CABLE) {
+			dst_set_fec(state, p->u.qam.fec_inner);
+			dst_set_symbolrate(state, p->u.qam.symbol_rate);
+			dst_set_modulation(state, p->u.qam.modulation);
+		}
+		dst_write_tuna(fe);
+	}
+
+	return 0;
+}
+
+static int dst_tune_frontend(struct dvb_frontend* fe,
 			    struct dvb_frontend_parameters* p,
 			    unsigned int mode_flags,
 			    int *delay,
@@ -1378,6 +1690,11 @@ static int dst_set_frontend(struct dvb_frontend* fe,
 	return 0;
 }
 
+static int dst_get_tuning_algo(struct dvb_frontend *fe)
+{
+	return dst_algo;
+}
+
 static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
 {
 	struct dst_state *state = fe->demodulator_priv;
@@ -1408,6 +1725,7 @@ static void dst_release(struct dvb_frontend *fe)
 static struct dvb_frontend_ops dst_dvbt_ops;
 static struct dvb_frontend_ops dst_dvbs_ops;
 static struct dvb_frontend_ops dst_dvbc_ops;
+static struct dvb_frontend_ops dst_atsc_ops;
 
 struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
 {
@@ -1417,24 +1735,25 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad
 		return NULL;
 	}
 	/* determine settings based on type */
+	/* create dvb_frontend */
 	switch (state->dst_type) {
 	case DST_TYPE_IS_TERR:
-		memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	case DST_TYPE_IS_CABLE:
-		memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	case DST_TYPE_IS_SAT:
-		memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	case DST_TYPE_IS_ATSC:
+		memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	default:
 		dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist.");
 		kfree(state);
 		return NULL;
 	}
-
-	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
 
 	return state;				/*	Manu (DST is a card not a frontend)	*/
@@ -1455,8 +1774,10 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
 
 	.release = dst_release,
 	.init = dst_init,
-	.tune = dst_set_frontend,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
 	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
 	.read_status = dst_read_status,
 	.read_signal_strength = dst_read_signal_strength,
 	.read_snr = dst_read_snr,
@@ -1479,8 +1800,10 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
 
 	.release = dst_release,
 	.init = dst_init,
-	.tune = dst_set_frontend,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
 	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
 	.read_status = dst_read_status,
 	.read_signal_strength = dst_read_signal_strength,
 	.read_snr = dst_read_snr,
@@ -1506,13 +1829,38 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
 
 	.release = dst_release,
 	.init = dst_init,
-	.tune = dst_set_frontend,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
+	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
+	.read_status = dst_read_status,
+	.read_signal_strength = dst_read_signal_strength,
+	.read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_atsc_ops = {
+	.info = {
+		.name = "DST ATSC",
+		.type = FE_ATSC,
+		.frequency_stepsize = 62500,
+		.frequency_min = 510000000,
+		.frequency_max = 858000000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.release = dst_release,
+	.init = dst_init,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
 	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
 	.read_status = dst_read_status,
 	.read_signal_strength = dst_read_signal_strength,
 	.read_snr = dst_read_snr,
 };
 
-MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
+MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver");
 MODULE_AUTHOR("Jamie Honan, Manu Abraham");
 MODULE_LICENSE("GPL");

+ 101 - 15
drivers/media/dvb/bt8xx/dst_ca.c

@@ -68,6 +68,13 @@ static int ca_set_pid(void)
 	return -EOPNOTSUPP;
 }
 
+static void put_command_and_length(u8 *data, int command, int length)
+{
+	data[0] = (command >> 16) & 0xff;
+	data[1] = (command >> 8) & 0xff;
+	data[2] = command & 0xff;
+	data[3] = length;
+}
 
 static void put_checksum(u8 *check_string, int length)
 {
@@ -124,15 +131,18 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string,
 	u8 dst_ca_comm_err = 0;
 
 	while (dst_ca_comm_err < RETRIES) {
-		dst_comm_init(state);
 		dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
 		if (dst_ci_command(state, data, ca_string, len, read)) {	// If error
 			dst_error_recovery(state);
 			dst_ca_comm_err++; // work required here.
+		} else {
+			break;
 		}
-		break;
 	}
 
+	if(dst_ca_comm_err == RETRIES)
+		return -1;
+
 	return 0;
 }
 
@@ -140,6 +150,7 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string,
 
 static int ca_get_app_info(struct dst_state *state)
 {
+	int length, str_length;
 	static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
 
 	put_checksum(&command[0], command[0]);
@@ -154,6 +165,68 @@ static int ca_get_app_info(struct dst_state *state)
 		(state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
 	dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
 
+	// Transform dst message to correct application_info message
+	length = state->messages[5];
+	str_length = length - 6;
+	if (str_length < 0) {
+		str_length = 0;
+		dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
+	}
+
+	// First, the command and length fields
+	put_command_and_length(&state->messages[0], CA_APP_INFO, length);
+
+	// Copy application_type, application_manufacturer and manufacturer_code
+	memcpy(&state->messages[4], &state->messages[7], 5);
+
+	// Set string length and copy string
+	state->messages[9] = str_length;
+	memcpy(&state->messages[10], &state->messages[12], str_length);
+
+	return 0;
+}
+
+static int ca_get_ca_info(struct dst_state *state)
+{
+	int srcPtr, dstPtr, i, num_ids;
+	static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
+	const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
+
+	put_checksum(&slot_command[0], slot_command[0]);
+	if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
+		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+		return -1;
+	}
+	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+	// Print raw data
+	dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
+	for (i = 0; i < state->messages[0] + 1; i++) {
+		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
+	}
+	dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+	// Set the command and length of the output
+	num_ids = state->messages[in_num_ids_pos];
+	if (num_ids >= 100) {
+		num_ids = 100;
+		dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
+	}
+	put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
+
+	dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
+	srcPtr = in_system_id_pos;
+	dstPtr = out_system_id_pos;
+	for(i = 0; i < num_ids; i++) {
+		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
+		// Append to output
+		state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
+		state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
+		srcPtr += 2;
+		dstPtr += 2;
+	}
+	dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
 	return 0;
 }
 
@@ -174,7 +247,7 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps,
 
 	dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
 	dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
-	for (i = 0; i < 8; i++)
+	for (i = 0; i < slot_cap[0] + 1; i++)
 		dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
 	dprintk(verbose, DST_CA_INFO, 0, "\n");
 
@@ -260,6 +333,11 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message,
 			if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
 				return -EFAULT;
 			break;
+		case CA_INFO:
+			memcpy(p_ca_message->msg, state->messages, 128);
+			if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+				return -EFAULT;
+			break;
 		}
 	}
 
@@ -302,7 +380,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l
 		rdc_reset_state(state);
 		return -1;
 	}
-	dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes.");
+	dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
 
 	return 0;
 }
@@ -340,6 +418,7 @@ static int debug_string(u8 *msg, u32 length, u32 offset)
 	return 0;
 }
 
+
 static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
 {
 	u32 length = 0;
@@ -455,6 +534,16 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
 			}
 			dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
 			break;
+		case CA_INFO_ENQUIRY:
+			dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
+
+			if ((ca_get_ca_info(state)) < 0) {
+				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
+				result = -1;
+				goto free_mem_and_exit;
+			}
+			dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
+			break;
 		}
 	}
 free_mem_and_exit:
@@ -473,18 +562,15 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 	void __user *arg = (void __user *)ioctl_arg;
 	int result = 0;
 
-	if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
-		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-		return -ENOMEM;
-	}
-	if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
+	p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
+	p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
+	p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
+	if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
 		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-		return -ENOMEM;
-	}
-	if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
-		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-		return -ENOMEM;
+		result = -ENOMEM;
+		goto free_mem_and_exit;
 	}
+
 	/*	We have now only the standard ioctl's, the driver is upposed to handle internals.	*/
 	switch (cmd) {
 	case CA_SEND_MSG:
@@ -582,7 +668,7 @@ static int dst_ca_release(struct inode *inode, struct file *file)
 
 static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
 {
-	int bytes_read = 0;
+	ssize_t bytes_read = 0;
 
 	dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
 

+ 29 - 4
drivers/media/dvb/bt8xx/dst_common.h

@@ -42,7 +42,7 @@
 #define DST_TYPE_IS_CABLE	2
 #define DST_TYPE_IS_ATSC	3
 
-#define DST_TYPE_HAS_NEWTUNE	1
+#define DST_TYPE_HAS_TS188	1
 #define DST_TYPE_HAS_TS204	2
 #define DST_TYPE_HAS_SYMDIV	4
 #define DST_TYPE_HAS_FW_1	8
@@ -52,6 +52,9 @@
 #define DST_TYPE_HAS_OBS_REGS	128
 #define DST_TYPE_HAS_INC_COUNT	256
 #define DST_TYPE_HAS_MULTI_FE	512
+#define DST_TYPE_HAS_NEWTUNE_2	1024
+#define DST_TYPE_HAS_DBOARD	2048
+#define DST_TYPE_HAS_VLF	4096
 
 /*	Card capability list	*/
 
@@ -64,6 +67,20 @@
 #define	DST_TYPE_HAS_ANALOG	64	/*	Analog inputs	*/
 #define DST_TYPE_HAS_SESSION	128
 
+#define TUNER_TYPE_MULTI	1
+#define TUNER_TYPE_UNKNOWN	2
+/*	DVB-S		*/
+#define TUNER_TYPE_L64724	4
+#define TUNER_TYPE_STV0299	8
+#define TUNER_TYPE_MB86A15	16
+
+/*	DVB-T		*/
+#define TUNER_TYPE_TDA10046	32
+
+/*	ATSC		*/
+#define TUNER_TYPE_NXT200x	64
+
+
 #define RDC_8820_PIO_0_DISABLE	0
 #define RDC_8820_PIO_0_ENABLE	1
 #define RDC_8820_INT		2
@@ -84,8 +101,6 @@ struct dst_state {
 
 	struct bt878* bt;
 
-	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct dst_config* config;
 
@@ -121,8 +136,17 @@ struct dst_state {
 	u8 card_info[8];
 	u8 vendor[8];
 	u8 board_info[8];
-
+	u32 tuner_type;
+	char *tuner_name;
 	struct mutex dst_mutex;
+	u8 fw_name[8];
+};
+
+struct tuner_types {
+	u32 tuner_type;
+	char *tuner_name;
+	char *board_name;
+	char *fw_name;
 };
 
 struct dst_types {
@@ -131,6 +155,7 @@ struct dst_types {
 	u8 dst_type;
 	u32 type_flags;
 	u32 dst_feature;
+	u32 tuner_type;
 };
 
 struct dst_config

+ 61 - 57
drivers/media/dvb/bt8xx/dvb-bt8xx.c

@@ -147,12 +147,15 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
 	return 0;
 }
 
-static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
 {
 	u32 div;
 	unsigned char bs = 0;
 	unsigned char cp = 0;
 
+	if (buf_len < 5)
+		return -EINVAL;
+
 	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
 	if (params->frequency < 542000000)
@@ -169,22 +172,25 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
 	else
 		bs = 0x08;
 
-	pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
+	pllbuf[0] = 0x60;
 	pllbuf[1] = div >> 8;
 	pllbuf[2] = div & 0xff;
 	pllbuf[3] = cp;
 	pllbuf[4] = bs;
 
-	return 0;
+	return 5;
 }
 
 static struct mt352_config thomson_dtt7579_config = {
 	.demod_address = 0x0f,
 	.demod_init = thomson_dtt7579_demod_init,
-	.pll_set = thomson_dtt7579_pll_set,
 };
 
-static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static struct zl10353_config thomson_dtt7579_zl10353_config = {
+	.demod_address = 0x0f,
+};
+
+static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	u32 freq = params->frequency;
 
@@ -237,7 +243,7 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete
 	return 0;
 }
 
-static int pinnsat_pll_init(struct dvb_frontend* fe)
+static int pinnsat_tuner_init(struct dvb_frontend* fe)
 {
 	struct dvb_bt8xx_card *card = fe->dvb->priv;
 
@@ -247,7 +253,7 @@ static int pinnsat_pll_init(struct dvb_frontend* fe)
 	return 0;
 }
 
-static int pinnsat_pll_sleep(struct dvb_frontend* fe)
+static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
 {
 	struct dvb_bt8xx_card *card = fe->dvb->priv;
 
@@ -258,12 +264,9 @@ static int pinnsat_pll_sleep(struct dvb_frontend* fe)
 
 static struct cx24110_config pctvsat_config = {
 	.demod_address = 0x55,
-	.pll_init = pinnsat_pll_init,
-	.pll_set = cx24108_pll_set,
-	.pll_sleep = pinnsat_pll_sleep,
 };
 
-static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
 	u8 cfg, cpump, band_select;
@@ -297,6 +300,8 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front
 	data[2] = ((div >> 10) & 0x60) | cfg;
 	data[3] = (cpump << 6) | band_select;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(card->i2c_adapter, &msg, 1);
 	return (div * 166666 - 36000000);
 }
@@ -310,7 +315,6 @@ static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const s
 
 static struct sp887x_config microtune_mt7202dtf_config = {
 	.demod_address = 0x70,
-	.pll_set = microtune_mt7202dtf_pll_set,
 	.request_firmware = microtune_mt7202dtf_request_firmware,
 };
 
@@ -337,12 +341,14 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
 	return 0;
 }
 
-static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
 {
 	u32 div;
 	unsigned char bs = 0;
 	unsigned char cp = 0;
 
+	if (buf_len < 5) return -EINVAL;
+
 	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
 	if (params->frequency < 150000000)
@@ -383,19 +389,18 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct
 	else
 		bs = 0x08;
 
-	pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+	pllbuf[0] = 0x61;
 	pllbuf[1] = div >> 8;
 	pllbuf[2] = div & 0xff;
 	pllbuf[3] = cp;
 	pllbuf[4] = bs;
 
-	return 0;
+	return 5;
 }
 
 static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
 	.demod_address = 0x0f,
 	.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
-	.pll_set = advbt771_samsung_tdtc9251dh0_pll_set,
 };
 
 static struct dst_config dst_config = {
@@ -455,7 +460,7 @@ static struct or51211_config or51211_config = {
 	.sleep = or51211_sleep,
 };
 
-static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
 	u8 buf[4];
@@ -478,6 +483,8 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
 	else
 		return -EINVAL;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(card->i2c_adapter, &msg, 1);
 	return 0;
 }
@@ -485,7 +492,6 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
 static struct nxt6000_config vp3021_alps_tded4_config = {
 	.demod_address = 0x0a,
 	.clock_inversion = 1,
-	.pll_set = vp3021_alps_tded4_pll_set,
 };
 
 static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
@@ -506,14 +512,17 @@ static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
 	return 0;
 }
 
-static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
 {
 	u32 div;
 	struct dvb_ofdm_parameters *op = &params->u.ofdm;
 
+	if (buf_len < 5)
+		return -EINVAL;
+
 	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
-	pllbuf[0] = 0xc2;
+	pllbuf[0] = 0x61;
 	pllbuf[1] = (div >> 8) & 0x7F;
 	pllbuf[2] = div & 0xFF;
 	pllbuf[3] = 0x85;
@@ -530,7 +539,7 @@ static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
 	if (op->bandwidth == 8)
 		pllbuf[4] |= 0x04;
 
-	return 0;
+	return 5;
 }
 
 static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
@@ -557,43 +566,18 @@ static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
 static struct mt352_config digitv_alps_tded4_config = {
 	.demod_address = 0x0a,
 	.demod_init = digitv_alps_tded4_demod_init,
-	.pll_set = digitv_alps_tded4_pll_set,
 };
 
-static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int tdvs_tua6034_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
-	u8 buf[4];
-	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-	int err;
-
-	dvb_pll_configure(&dvb_pll_tdvs_tua6034, buf, params->frequency, 0);
-	dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
-		__FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
-	if ((err = i2c_transfer(card->i2c_adapter, &msg, 1)) != 1) {
-		printk(KERN_WARNING "dvb-bt8xx: %s error "
-			"(addr %02x <- %02x, err = %i)\n",
-			__FUNCTION__, buf[0], buf[1], err);
-		if (err < 0)
-			return err;
-		else
-			return -EREMOTEIO;
-	}
-
-	/* Set the Auxiliary Byte. */
-	buf[2] &= ~0x20;
-	buf[2] |= 0x18;
-	buf[3] = 0x50;
-	i2c_transfer(card->i2c_adapter, &msg, 1);
-
-	return 0;
+	return lg_h06xf_pll_set(fe, card->i2c_adapter, params);
 }
 
 static struct lgdt330x_config tdvs_tua6034_config = {
 	.demod_address    = 0x0e,
 	.demod_chip       = LGDT3303,
 	.serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
-	.pll_set          = tdvs_tua6034_pll_set,
 };
 
 static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
@@ -617,17 +601,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 	switch(type) {
 	case BTTV_BOARD_DVICO_DVBT_LITE:
 		card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
+
+		if (card->fe == NULL)
+			card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config,
+						  card->i2c_adapter);
+
 		if (card->fe != NULL) {
-			card->fe->ops->info.frequency_min = 174000000;
-			card->fe->ops->info.frequency_max = 862000000;
+			card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
+			card->fe->ops.info.frequency_min = 174000000;
+			card->fe->ops.info.frequency_max = 862000000;
 		}
 		break;
 
 	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
 		lgdt330x_reset(card);
 		card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
-		if (card->fe != NULL)
+		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
 			dprintk ("dvb_bt8xx: lgdt330x detected\n");
+		}
 		break;
 
 	case BTTV_BOARD_NEBULA_DIGITV:
@@ -640,6 +632,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 		digitv_alps_tded4_reset(card);
 		card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
 		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
 			dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
 			break;
 		}
@@ -648,19 +641,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 		digitv_alps_tded4_reset(card);
 		card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter);
 
-		if (card->fe != NULL)
+		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
 			dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
+		}
 		break;
 
 	case BTTV_BOARD_AVDVBT_761:
 		card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
+		if (card->fe) {
+			card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
+		}
 		break;
 
 	case BTTV_BOARD_AVDVBT_771:
 		card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
 		if (card->fe != NULL) {
-			card->fe->ops->info.frequency_min = 174000000;
-			card->fe->ops->info.frequency_max = 862000000;
+			card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
+			card->fe->ops.info.frequency_min = 174000000;
+			card->fe->ops.info.frequency_max = 862000000;
 		}
 		break;
 
@@ -687,6 +686,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 
 	case BTTV_BOARD_PINNACLESAT:
 		card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
+		if (card->fe) {
+			card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
+			card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
+			card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
+		}
 		break;
 
 	case BTTV_BOARD_PC_HDTV:
@@ -703,8 +707,8 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 	else
 		if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
 			printk("dvb-bt8xx: Frontend registration failed!\n");
-			if (card->fe->ops->release)
-				card->fe->ops->release(card->fe);
+			if (card->fe->ops.release)
+				card->fe->ops.release(card->fe);
 			card->fe = NULL;
 		}
 }
@@ -713,7 +717,7 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
 {
 	int result;
 
-	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) {
+	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE, &card->bt->dev->dev)) < 0) {
 		printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
 		return result;
 	}

+ 2 - 0
drivers/media/dvb/bt8xx/dvb-bt8xx.h

@@ -37,6 +37,8 @@
 #include "cx24110.h"
 #include "or51211.h"
 #include "lgdt330x.h"
+#include "lg_h06xf.h"
+#include "zl10353.h"
 
 struct dvb_bt8xx_card {
 	struct mutex lock;

+ 1 - 1
drivers/media/dvb/cinergyT2/Kconfig

@@ -64,7 +64,7 @@ config DVB_CINERGYT2_QUERY_INTERVAL
 config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
 	bool "Register the onboard IR Remote Control Receiver as Input Device"
 	depends on DVB_CINERGYT2_TUNING
-	default "yes"
+	default y
 	help
 	  Enable this option if you want to use the onboard Infrared Remote
 	  Control Receiver as Linux-Input device.

+ 6 - 2
drivers/media/dvb/cinergyT2/cinergyT2.c

@@ -544,15 +544,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;
 
 	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	poll_wait(file, &cinergyt2->poll_wq, wait);
 
+       if (cinergyt2->pending_fe_events != 0)
+		mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
 	mutex_unlock(&cinergyt2->sem);
 
-	return (POLLIN | POLLRDNORM | POLLPRI);
+       return mask;
 }
 
 
@@ -902,7 +906,7 @@ static int cinergyt2_probe (struct usb_interface *intf,
 		return -ENOMEM;
 	}
 
-	if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE)) < 0) {
+	if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE, &cinergyt2->udev->dev)) < 0) {
 		kfree(cinergyt2);
 		return err;
 	}

+ 3 - 3
drivers/media/dvb/dvb-core/Makefile

@@ -2,8 +2,8 @@
 # Makefile for the kernel DVB device drivers.
 #
 
-dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
-		dvb_ca_en50221.o dvb_frontend.o \
-		dvb_net.o dvb_ringbuffer.o
+dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o 	\
+		dvb_ca_en50221.o dvb_frontend.o 		\
+		dvb_net.o dvb_ringbuffer.o dvb_math.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o

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

@@ -872,9 +872,6 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
-	case DMX_GET_EVENT:
-		break;
-
 	case DMX_GET_PES_PIDS:
 		if (!dmxdev->demux->get_pes_pids) {
 			ret = -EINVAL;

+ 23 - 2
drivers/media/dvb/dvb-core/dvb_ca_en50221.c

@@ -1060,8 +1060,18 @@ static int dvb_ca_en50221_thread(void *data)
 				break;
 
 			case DVB_CA_SLOTSTATE_VALIDATE:
-				if (dvb_ca_en50221_parse_attributes(ca, slot)
-				    != 0) {
+				if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+					/* we need this extra check for annoying interfaces like the budget-av */
+					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+					    (ca->pub->poll_slot_status)) {
+						int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+							dvb_ca_en50221_thread_update_delay(ca);
+							break;
+						}
+					}
+
 					printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
 					       ca->dvbdev->adapter->num);
 					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
@@ -1108,6 +1118,17 @@ static int dvb_ca_en50221_thread(void *data)
 
 			case DVB_CA_SLOTSTATE_LINKINIT:
 				if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+					/* we need this extra check for annoying interfaces like the budget-av */
+					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+					    (ca->pub->poll_slot_status)) {
+						int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+							dvb_ca_en50221_thread_update_delay(ca);
+							break;
+						}
+					}
+
 					printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
 					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
 					dvb_ca_en50221_thread_update_delay(ca);

+ 2 - 2
drivers/media/dvb/dvb-core/dvb_demux.c

@@ -473,7 +473,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 			goto bailout;
 		}
 		memcpy(&demux->tsbuf[i], buf, j);
-		if ((demux->tsbuf[0] == 0x47) | (demux->tsbuf[0] == 0xB8)) {
+		if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
 			memcpy(tmppack, demux->tsbuf, 188);
 			if (tmppack[0] == 0xB8)
 				tmppack[0] = 0x47;
@@ -484,7 +484,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 	}
 
 	while (p < count) {
-		if ((buf[p] == 0x47) | (buf[p] == 0xB8)) {
+		if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
 			if (count - p >= 204) {
 				memcpy(tmppack, &buf[p], 188);
 				if (tmppack[0] == 0xB8)

+ 85 - 66
drivers/media/dvb/dvb-core/dvb_frontend.c

@@ -56,7 +56,7 @@ MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AU
 module_param(dvb_override_tune_delay, int, 0644);
 MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
 module_param(dvb_powerdown_on_sleep, int, 0644);
-MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
 
 #define dprintk if (dvb_frontend_debug) printk
 
@@ -72,6 +72,8 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB vola
 #define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
 #define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
 #define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+
+#define FE_ALGO_HW		1
 /*
  * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
  * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
@@ -151,8 +153,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 		sizeof (struct dvb_frontend_parameters));
 
 	if (status & FE_HAS_LOCK)
-		if (fe->ops->get_frontend)
-			fe->ops->get_frontend(fe, &e->parameters);
+		if (fe->ops.get_frontend)
+			fe->ops.get_frontend(fe, &e->parameters);
 
 	events->eventw = wp;
 
@@ -211,10 +213,15 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
 {
 	dprintk ("DVB: initialising frontend %i (%s)...\n",
 		 fe->dvb->num,
-		 fe->ops->info.name);
-
-	if (fe->ops->init)
-		fe->ops->init(fe);
+		 fe->ops.info.name);
+
+	if (fe->ops.init)
+		fe->ops.init(fe);
+	if (fe->ops.tuner_ops.init) {
+		fe->ops.tuner_ops.init(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 }
 
 void dvb_frontend_reinitialise(struct dvb_frontend *fe)
@@ -259,7 +266,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
 	u32 original_frequency = fepriv->parameters.frequency;
 
 	/* are we using autoinversion? */
-	autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+	autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
 			 (fepriv->parameters.inversion == INVERSION_AUTO));
 
 	/* setup parameters correctly */
@@ -329,8 +336,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
 	fepriv->parameters.frequency += fepriv->lnb_drift;
 	if (autoinversion)
 		fepriv->parameters.inversion = fepriv->inversion;
-	if (fe->ops->set_frontend)
-		fe->ops->set_frontend(fe, &fepriv->parameters);
+	if (fe->ops.set_frontend)
+		fe->ops.set_frontend(fe, &fepriv->parameters);
 
 	fepriv->parameters.frequency = original_frequency;
 	fepriv->parameters.inversion = original_inversion;
@@ -354,8 +361,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
 	/* in SCAN mode, we just set the frontend when asked and leave it alone */
 	if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
 		if (fepriv->state & FESTATE_RETUNE) {
-			if (fe->ops->set_frontend)
-				fe->ops->set_frontend(fe, &fepriv->parameters);
+			if (fe->ops.set_frontend)
+				fe->ops.set_frontend(fe, &fepriv->parameters);
 			fepriv->state = FESTATE_TUNED;
 		}
 		fepriv->delay = 3*HZ;
@@ -367,8 +374,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
 	if (fepriv->state & FESTATE_RETUNE) {
 		s = 0;
 	} else {
-		if (fe->ops->read_status)
-			fe->ops->read_status(fe, &s);
+		if (fe->ops.read_status)
+			fe->ops.read_status(fe, &s);
 		if (s != fepriv->status) {
 			dvb_frontend_add_event(fe, s);
 			fepriv->status = s;
@@ -381,7 +388,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
 		fepriv->state = FESTATE_TUNED;
 
 		/* if we're tuned, then we have determined the correct inversion */
-		if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+		if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
 		    (fepriv->parameters.inversion == INVERSION_AUTO)) {
 			fepriv->parameters.inversion = fepriv->inversion;
 		}
@@ -405,7 +412,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
 	/* don't actually do anything if we're in the LOSTLOCK state,
 	 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
 	if ((fepriv->state & FESTATE_LOSTLOCK) &&
-	    (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+	    (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
 		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
 		return;
 	}
@@ -540,16 +547,16 @@ static int dvb_frontend_thread(void *data)
 		if (fepriv->reinitialise) {
 			dvb_frontend_init(fe);
 			if (fepriv->tone != -1) {
-				fe->ops->set_tone(fe, fepriv->tone);
+				fe->ops.set_tone(fe, fepriv->tone);
 			}
 			if (fepriv->voltage != -1) {
-				fe->ops->set_voltage(fe, fepriv->voltage);
+				fe->ops.set_voltage(fe, fepriv->voltage);
 			}
 			fepriv->reinitialise = 0;
 		}
 
 		/* do an iteration of the tuning loop */
-		if (fe->ops->tune) {
+		if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
 			/* have we been asked to retune? */
 			params = NULL;
 			if (fepriv->state & FESTATE_RETUNE) {
@@ -557,7 +564,7 @@ static int dvb_frontend_thread(void *data)
 				fepriv->state = FESTATE_TUNED;
 			}
 
-			fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+			fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
 			if (s != fepriv->status) {
 				dvb_frontend_add_event(fe, s);
 				fepriv->status = s;
@@ -569,10 +576,15 @@ static int dvb_frontend_thread(void *data)
 
 	if (dvb_shutdown_timeout) {
 		if (dvb_powerdown_on_sleep)
-			if (fe->ops->set_voltage)
-				fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF);
-		if (fe->ops->sleep)
-			fe->ops->sleep(fe);
+			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)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (fe->ops.sleep)
+			fe->ops.sleep(fe);
 	}
 
 	fepriv->thread_pid = 0;
@@ -724,7 +736,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 	switch (cmd) {
 	case FE_GET_INFO: {
 		struct dvb_frontend_info* info = parg;
-		memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info));
+		memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
 
 		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
 		 * do it, it is done for it. */
@@ -744,58 +756,58 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			break;
 		}
 
-		if (fe->ops->read_status)
-			err = fe->ops->read_status(fe, status);
+		if (fe->ops.read_status)
+			err = fe->ops.read_status(fe, status);
 		break;
 	}
 	case FE_READ_BER:
-		if (fe->ops->read_ber)
-			err = fe->ops->read_ber(fe, (__u32*) parg);
+		if (fe->ops.read_ber)
+			err = fe->ops.read_ber(fe, (__u32*) parg);
 		break;
 
 	case FE_READ_SIGNAL_STRENGTH:
-		if (fe->ops->read_signal_strength)
-			err = fe->ops->read_signal_strength(fe, (__u16*) parg);
+		if (fe->ops.read_signal_strength)
+			err = fe->ops.read_signal_strength(fe, (__u16*) parg);
 		break;
 
 	case FE_READ_SNR:
-		if (fe->ops->read_snr)
-			err = fe->ops->read_snr(fe, (__u16*) parg);
+		if (fe->ops.read_snr)
+			err = fe->ops.read_snr(fe, (__u16*) parg);
 		break;
 
 	case FE_READ_UNCORRECTED_BLOCKS:
-		if (fe->ops->read_ucblocks)
-			err = fe->ops->read_ucblocks(fe, (__u32*) parg);
+		if (fe->ops.read_ucblocks)
+			err = fe->ops.read_ucblocks(fe, (__u32*) parg);
 		break;
 
 
 	case FE_DISEQC_RESET_OVERLOAD:
-		if (fe->ops->diseqc_reset_overload) {
-			err = fe->ops->diseqc_reset_overload(fe);
+		if (fe->ops.diseqc_reset_overload) {
+			err = fe->ops.diseqc_reset_overload(fe);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
 		}
 		break;
 
 	case FE_DISEQC_SEND_MASTER_CMD:
-		if (fe->ops->diseqc_send_master_cmd) {
-			err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+		if (fe->ops.diseqc_send_master_cmd) {
+			err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
 		}
 		break;
 
 	case FE_DISEQC_SEND_BURST:
-		if (fe->ops->diseqc_send_burst) {
-			err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+		if (fe->ops.diseqc_send_burst) {
+			err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
 		}
 		break;
 
 	case FE_SET_TONE:
-		if (fe->ops->set_tone) {
-			err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
+		if (fe->ops.set_tone) {
+			err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
 			fepriv->tone = (fe_sec_tone_mode_t) parg;
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
@@ -803,8 +815,8 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 		break;
 
 	case FE_SET_VOLTAGE:
-		if (fe->ops->set_voltage) {
-			err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
+		if (fe->ops.set_voltage) {
+			err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
 			fepriv->voltage = (fe_sec_voltage_t) parg;
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
@@ -812,11 +824,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 		break;
 
 	case FE_DISHNETWORK_SEND_LEGACY_CMD:
-		if (fe->ops->dishnetwork_send_legacy_command) {
-			err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
+		if (fe->ops.dishnetwork_send_legacy_command) {
+			err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
-		} else if (fe->ops->set_voltage) {
+		} else if (fe->ops.set_voltage) {
 			/*
 			 * NOTE: This is a fallback condition.  Some frontends
 			 * (stv0299 for instance) take longer than 8msec to
@@ -846,7 +858,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			/* before sending a command, initialize by sending
 			 * a 32ms 18V to the switch
 			 */
-			fe->ops->set_voltage(fe, SEC_VOLTAGE_18);
+			fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
 			dvb_frontend_sleep_until(&nexttime, 32000);
 
 			for (i = 0; i < 9; i++) {
@@ -854,7 +866,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 					do_gettimeofday(&tv[i + 1]);
 				if ((cmd & 0x01) != last) {
 					/* set voltage to (last ? 13V : 18V) */
-					fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+					fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
 					last = (last) ? 0 : 1;
 				}
 				cmd = cmd >> 1;
@@ -874,13 +886,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 		break;
 
 	case FE_DISEQC_RECV_SLAVE_REPLY:
-		if (fe->ops->diseqc_recv_slave_reply)
-			err = fe->ops->diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+		if (fe->ops.diseqc_recv_slave_reply)
+			err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
 		break;
 
 	case FE_ENABLE_HIGH_LNB_VOLTAGE:
-		if (fe->ops->enable_high_lnb_voltage)
-			err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
+		if (fe->ops.enable_high_lnb_voltage)
+			err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
 		break;
 
 	case FE_SET_FRONTEND: {
@@ -898,7 +910,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			fepriv->parameters.inversion = INVERSION_AUTO;
 			fetunesettings.parameters.inversion = INVERSION_AUTO;
 		}
-		if (fe->ops->info.type == FE_OFDM) {
+		if (fe->ops.info.type == FE_OFDM) {
 			/* without hierachical coding code_rate_LP is irrelevant,
 			 * so we tolerate the otherwise invalid FEC_NONE setting */
 			if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
@@ -907,13 +919,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 		}
 
 		/* get frontend-specific tuning settings */
-		if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) {
+		if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
 			fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
 			fepriv->max_drift = fetunesettings.max_drift;
 			fepriv->step_size = fetunesettings.step_size;
 		} else {
 			/* default values */
-			switch(fe->ops->info.type) {
+			switch(fe->ops.info.type) {
 			case FE_QPSK:
 				fepriv->min_delay = HZ/20;
 				fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
@@ -928,11 +940,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
 			case FE_OFDM:
 				fepriv->min_delay = HZ/20;
-				fepriv->step_size = fe->ops->info.frequency_stepsize * 2;
-				fepriv->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
+				fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+				fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
 				break;
 			case FE_ATSC:
-				printk("dvb-core: FE_ATSC not handled yet.\n");
+				fepriv->min_delay = HZ/20;
+				fepriv->step_size = 0;
+				fepriv->max_drift = 0;
 				break;
 			}
 		}
@@ -952,9 +966,9 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 		break;
 
 	case FE_GET_FRONTEND:
-		if (fe->ops->get_frontend) {
+		if (fe->ops.get_frontend) {
 			memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
-			err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
+			err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
 		}
 		break;
 
@@ -1067,7 +1081,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
 
 	printk ("DVB: registering frontend %i (%s)...\n",
 		fe->dvb->num,
-		fe->ops->info.name);
+		fe->ops.info.name);
 
 	dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
 			     fe, DVB_DEVICE_FRONTEND);
@@ -1085,10 +1099,15 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
 	mutex_lock(&frontend_mutex);
 	dvb_unregister_device (fepriv->dvbdev);
 	dvb_frontend_stop (fe);
-	if (fe->ops->release)
-		fe->ops->release(fe);
+	if (fe->ops.tuner_ops.release) {
+		fe->ops.tuner_ops.release(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+	if (fe->ops.release)
+		fe->ops.release(fe);
 	else
-		printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
+		printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name);
 	/* fe is invalid now */
 	kfree(fepriv);
 	mutex_unlock(&frontend_mutex);

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

@@ -49,6 +49,44 @@ struct dvb_frontend_tune_settings {
 
 struct dvb_frontend;
 
+struct dvb_tuner_info {
+	char name[128];
+
+	u32 frequency_min;
+	u32 frequency_max;
+	u32 frequency_step;
+
+	u32 bandwidth_min;
+	u32 bandwidth_max;
+	u32 bandwidth_step;
+};
+
+struct dvb_tuner_ops {
+
+	struct dvb_tuner_info info;
+
+	int (*release)(struct dvb_frontend *fe);
+	int (*init)(struct dvb_frontend *fe);
+	int (*sleep)(struct dvb_frontend *fe);
+
+	/** This is for simple PLLs - set all parameters in one go. */
+	int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_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);
+
+	int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+
+#define TUNER_STATUS_LOCKED 1
+	int (*get_status)(struct dvb_frontend *fe, u32 *status);
+
+	/** These are provided seperately from set_params in order to facilitate silicon
+	 * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
+	int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+	int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+};
+
 struct dvb_frontend_ops {
 
 	struct dvb_frontend_info info;
@@ -64,6 +102,8 @@ struct dvb_frontend_ops {
 		    unsigned int mode_flags,
 		    int *delay,
 		    fe_status_t *status);
+	/* get frontend tuning algorithm from the module */
+	int (*get_frontend_algo)(struct dvb_frontend *fe);
 
 	/* these two are only used for the swzigzag code */
 	int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
@@ -86,6 +126,8 @@ struct dvb_frontend_ops {
 	int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
 	int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
 	int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+
+	struct dvb_tuner_ops tuner_ops;
 };
 
 #define MAX_EVENT 8
@@ -100,9 +142,10 @@ struct dvb_fe_events {
 };
 
 struct dvb_frontend {
-	struct dvb_frontend_ops* ops;
+	struct dvb_frontend_ops ops;
 	struct dvb_adapter *dvb;
 	void* demodulator_priv;
+	void* tuner_priv;
 	void* frontend_priv;
 	void* misc_priv;
 };

+ 145 - 0
drivers/media/dvb/dvb-core/dvb_math.c

@@ -0,0 +1,145 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/bug.h>
+#include "dvb_math.h"
+
+static const unsigned short logtable[256] = {
+	0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+	0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+	0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+	0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+	0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+	0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+	0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+	0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+	0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+	0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+	0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+	0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+	0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+	0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+	0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+	0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+	0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+	0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+	0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+	0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+	0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+	0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+	0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+	0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+	0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+	0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+	0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+	0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+	0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+	0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+	0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+	0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+};
+
+unsigned int intlog2(u32 value)
+{
+	/**
+	 *	returns: log2(value) * 2^24
+	 *	wrong result if value = 0 (log2(0) is undefined)
+	 */
+	unsigned int msb;
+	unsigned int logentry;
+	unsigned int significand;
+	unsigned int interpolation;
+
+	if (unlikely(value == 0)) {
+		WARN_ON(1);
+		return 0;
+	}
+
+	/* first detect the msb (count begins at 0) */
+	msb = fls(value) - 1;
+
+	/**
+	 *	now we use a logtable after the following method:
+	 *
+	 *	log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+	 *	where x = msb and therefore 1 <= y < 2
+	 *	first y is determined by shifting the value left
+	 *	so that msb is bit 31
+	 *		0x00231f56 -> 0x8C7D5800
+	 *	the result is y * 2^31 -> "significand"
+	 *	then the highest 9 bits are used for a table lookup
+	 *	the highest bit is discarded because it's always set
+	 *	the highest nine bits in our example are 100011000
+	 *	so we would use the entry 0x18
+	 */
+	significand = value << (31 - msb);
+	logentry = (significand >> 23) & 0xff;
+
+	/**
+	 *	last step we do is interpolation because of the
+	 *	limitations of the log table the error is that part of
+	 *	the significand which isn't used for lookup then we
+	 *	compute the ratio between the error and the next table entry
+	 *	and interpolate it between the log table entry used and the
+	 *	next one the biggest error possible is 0x7fffff
+	 *	(in our example it's 0x7D5800)
+	 *	needed value for next table entry is 0x800000
+	 *	so the interpolation is
+	 *	(error / 0x800000) * (logtable_next - logtable_current)
+	 *	in the implementation the division is moved to the end for
+	 *	better accuracy there is also an overflow correction if
+	 *	logtable_next is 256
+	 */
+	interpolation = ((significand & 0x7fffff) *
+			((logtable[(logentry + 1) & 0xff] -
+			  logtable[logentry]) & 0xffff)) >> 15;
+
+	/* now we return the result */
+	return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+}
+EXPORT_SYMBOL(intlog2);
+
+unsigned int intlog10(u32 value)
+{
+	/**
+	 *	returns: log10(value) * 2^24
+	 *	wrong result if value = 0 (log10(0) is undefined)
+	 */
+	u64 log;
+
+	if (unlikely(value == 0)) {
+		WARN_ON(1);
+		return 0;
+	}
+
+	log = intlog2(value);
+
+	/**
+	 *	we use the following method:
+	 *	log10(x) = log2(x) * log10(2)
+	 */
+
+	return (log * 646456993) >> 31;
+}
+EXPORT_SYMBOL(intlog10);

+ 58 - 0
drivers/media/dvb/dvb-core/dvb_math.h

@@ -0,0 +1,58 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __DVB_MATH_H
+#define __DVB_MATH_H
+
+#include <linux/types.h>
+
+/**
+ * computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
+ *
+ * example: intlog2(8) will give 3 << 24 = 3 * 2^24
+ * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
+ * @param value The value (must be != 0)
+ * @return log2(value) * 2^24
+ */
+extern unsigned int intlog2(u32 value);
+
+/**
+ * computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
+ *
+ * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
+ *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
+ *
+ * look at intlog2 for similar examples
+ *
+ * @param value The value (must be != 0)
+ * @return log10(value) * 2^24
+ */
+extern unsigned int intlog10(u32 value);
+
+#endif

+ 154 - 76
drivers/media/dvb/dvb-core/dvb_net.c

@@ -12,7 +12,7 @@
  *                          Hilmar Linder <hlinder@cosy.sbg.ac.at>
  *                      and Wolfram Stering <wstering@cosy.sbg.ac.at>
  *
- * ULE Decaps according to draft-ietf-ipdvb-ule-03.txt.
+ * ULE Decaps according to RFC 4326.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -42,6 +42,9 @@
  *                     Bugfixes and robustness improvements.
  *                     Filtering on dest MAC addresses, if present (D-Bit = 0)
  *                     ULE_DEBUG compile-time option.
+ * Apr 2006: cp v3:    Bugfixes and compliency with RFC 4326 (ULE) by
+ *                       Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
+ *                       Paris Lodron University of Salzburg.
  */
 
 /*
@@ -49,9 +52,6 @@
  *
  * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
  *
- * TS_FEED callback is called once for every single TS cell although it is
- * registered (in dvb_net_feed_start()) for 100 TS cells (used for dvb_net_ule()).
- *
  */
 
 #include <linux/module.h>
@@ -89,6 +89,9 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
 
 #ifdef ULE_DEBUG
 
+#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
+
 #define isprint(c)	((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
 
 static void hexdump( const unsigned char *buf, unsigned short len )
@@ -214,6 +217,8 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,
 #define ULE_TEST	0
 #define ULE_BRIDGED	1
 
+#define ULE_OPTEXTHDR_PADDING 0
+
 static int ule_test_sndu( struct dvb_net_priv *p )
 {
 	return -1;
@@ -221,14 +226,28 @@ static int ule_test_sndu( struct dvb_net_priv *p )
 
 static int ule_bridged_sndu( struct dvb_net_priv *p )
 {
-	/* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt.
-	 * This has to be the last extension header, otherwise it won't work.
-	 * Blame the authors!
+	struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
+	if(ntohs(hdr->h_proto) < 1536) {
+		int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
+		/* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
+		if(framelen != ntohs(hdr->h_proto)) {
+			return -1;
+		}
+	}
+	/* Note:
+	 * From RFC4326:
+	 *  "A bridged SNDU is a Mandatory Extension Header of Type 1.
+	 *   It must be the final (or only) extension header specified in the header chain of a SNDU."
+	 * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
 	 */
 	p->ule_bridged = 1;
 	return 0;
 }
 
+static int ule_exthdr_padding(struct dvb_net_priv *p)
+{
+	return 0;
+}
 
 /** Handle ULE extension headers.
  *  Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
@@ -242,7 +261,8 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
 		{ [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL,  };
 
 	/* Table of optional extension header handlers.  The header type is the index. */
-	static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = { NULL, };
+	static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
+		{ [0] = ule_exthdr_padding, [1] = NULL, };
 
 	int ext_len = 0;
 	unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
@@ -253,25 +273,31 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
 		/* Mandatory extension header */
 		if (ule_mandatory_ext_handlers[htype]) {
 			ext_len = ule_mandatory_ext_handlers[htype]( p );
-			p->ule_next_hdr += ext_len;
-			if (! p->ule_bridged) {
-				p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
-				p->ule_next_hdr += 2;
-			} else {
-				p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)) );
-				/* This assures the extension handling loop will terminate. */
+			if(ext_len >= 0) {
+				p->ule_next_hdr += ext_len;
+				if (!p->ule_bridged) {
+					p->ule_sndu_type = ntohs(*(unsigned short *)p->ule_next_hdr);
+					p->ule_next_hdr += 2;
+				} else {
+					p->ule_sndu_type = ntohs(*(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
+					/* This assures the extension handling loop will terminate. */
+				}
 			}
+			// else: extension handler failed or SNDU should be discarded
 		} else
 			ext_len = -1;	/* SNDU has to be discarded. */
 	} else {
 		/* Optional extension header.  Calculate the length. */
-		ext_len = hlen << 2;
+		ext_len = hlen << 1;
 		/* Process the optional extension header according to its type. */
 		if (ule_optional_ext_handlers[htype])
 			(void)ule_optional_ext_handlers[htype]( p );
 		p->ule_next_hdr += ext_len;
-		p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
-		p->ule_next_hdr += 2;
+		p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr-2) );
+		/*
+		 * note: the length of the next header type is included in the
+		 * length of THIS optional extension header
+		 */
 	}
 
 	return ext_len;
@@ -284,8 +310,14 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
 	p->ule_next_hdr = p->ule_skb->data;
 	do {
 		l = handle_one_ule_extension( p );
-		if (l == -1) return -1;	/* Stop extension header processing and discard SNDU. */
+		if (l < 0)
+			return l;	/* Stop extension header processing and discard SNDU. */
 		total_ext_len += l;
+#ifdef ULE_DEBUG
+		dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
+			"l=%i, total_ext_len=%i\n", p->ule_next_hdr,
+			(int) p->ule_sndu_type, l, total_ext_len);
+#endif
 
 	} while (p->ule_sndu_type < 1536);
 
@@ -355,8 +387,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 				if (priv->ule_skb) {
 					dev_kfree_skb( priv->ule_skb );
 					/* Prepare for next SNDU. */
-					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-					((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+					priv->stats.rx_errors++;
+					priv->stats.rx_frame_errors++;
 				}
 				reset_ule(priv);
 				priv->need_pusi = 1;
@@ -396,27 +428,25 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 			}
 		}
 
-		/* Check continuity counter. */
 		if (new_ts) {
+			/* Check continuity counter. */
 			if ((ts[3] & 0x0F) == priv->tscc)
 				priv->tscc = (priv->tscc + 1) & 0x0F;
 			else {
 				/* TS discontinuity handling: */
 				printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
-				       "exptected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
+				       "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
 				/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 				if (priv->ule_skb) {
 					dev_kfree_skb( priv->ule_skb );
 					/* Prepare for next SNDU. */
 					// reset_ule(priv);  moved to below.
-					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-					((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+					priv->stats.rx_errors++;
+					priv->stats.rx_frame_errors++;
 				}
 				reset_ule(priv);
 				/* skip to next PUSI. */
 				priv->need_pusi = 1;
-				ts += TS_SZ;
-				priv->ts_count++;
 				continue;
 			}
 			/* If we still have an incomplete payload, but PUSI is
@@ -425,7 +455,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 			 * cells (continuity counter wrap). */
 			if (ts[1] & TS_PUSI) {
 				if (! priv->need_pusi) {
-					if (*from_where > 181) {
+					if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
 						/* Pointer field is invalid.  Drop this TS cell and any started ULE SNDU. */
 						printk(KERN_WARNING "%lu: Invalid pointer "
 						       "field: %u.\n", priv->ts_count, *from_where);
@@ -438,8 +468,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 						}
 						reset_ule(priv);
 						priv->need_pusi = 1;
-						ts += TS_SZ;
-						priv->ts_count++;
 						continue;
 					}
 					/* Skip pointer field (we're processing a
@@ -452,8 +480,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 				if (priv->ule_sndu_remain > 183) {
 					/* Current SNDU lacks more data than there could be available in the
 					 * current TS cell. */
-					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-					((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;
+					priv->stats.rx_errors++;
+					priv->stats.rx_length_errors++;
 					printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
 					       "got PUSI (pf %d, ts_remain %d).  Flushing incomplete payload.\n",
 					       priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
@@ -492,9 +520,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 				} else
 					priv->ule_dbit = 0;
 
-				if (priv->ule_sndu_len > 32763) {
+				if (priv->ule_sndu_len < 5) {
 					printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
 					       "Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
+					priv->stats.rx_errors++;
+					priv->stats.rx_length_errors++;
 					priv->ule_sndu_len = 0;
 					priv->need_pusi = 1;
 					new_ts = 1;
@@ -608,58 +638,103 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 				ule_dump = 1;
 #endif
 
-				((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-				((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++;
+				priv->stats.rx_errors++;
+				priv->stats.rx_crc_errors++;
 				dev_kfree_skb(priv->ule_skb);
 			} else {
 				/* CRC32 verified OK. */
+				u8 dest_addr[ETH_ALEN];
+				static const u8 bc_addr[ETH_ALEN] =
+					{ [ 0 ... ETH_ALEN-1] = 0xff };
+
+				/* CRC32 was OK. Remove it from skb. */
+				priv->ule_skb->tail -= 4;
+				priv->ule_skb->len -= 4;
+
+				if (!priv->ule_dbit) {
+					/*
+					 * The destination MAC address is the
+					 * next data in the skb.  It comes
+					 * before any extension headers.
+					 *
+					 * Check if the payload of this SNDU
+					 * should be passed up the stack.
+					 */
+					register int drop = 0;
+					if (priv->rx_mode != RX_MODE_PROMISC) {
+						if (priv->ule_skb->data[0] & 0x01) {
+							/* multicast or broadcast */
+							if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
+								/* multicast */
+								if (priv->rx_mode == RX_MODE_MULTI) {
+									int i;
+									for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
+										;
+									if (i == priv->multi_num)
+										drop = 1;
+								} else if (priv->rx_mode != RX_MODE_ALL_MULTI)
+									drop = 1; /* no broadcast; */
+								/* else: all multicast mode: accept all multicast packets */
+							}
+							/* else: broadcast */
+						}
+						else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
+							drop = 1;
+						/* else: destination address matches the MAC address of our receiver device */
+					}
+					/* else: promiscious mode; pass everything up the stack */
+
+					if (drop) {
+#ifdef ULE_DEBUG
+						dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
+							MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+#endif
+						dev_kfree_skb(priv->ule_skb);
+						goto sndu_done;
+					}
+					else
+					{
+						memcpy(dest_addr,  priv->ule_skb->data, ETH_ALEN);
+						skb_pull(priv->ule_skb, ETH_ALEN);
+					}
+				}
+
 				/* Handle ULE Extension Headers. */
 				if (priv->ule_sndu_type < 1536) {
 					/* There is an extension header.  Handle it accordingly. */
-					int l = handle_ule_extensions( priv );
+					int l = handle_ule_extensions(priv);
 					if (l < 0) {
 						/* Mandatory extension header unknown or TEST SNDU.  Drop it. */
 						// printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
-						dev_kfree_skb( priv->ule_skb );
+						dev_kfree_skb(priv->ule_skb);
 						goto sndu_done;
 					}
-					skb_pull( priv->ule_skb, l );
+					skb_pull(priv->ule_skb, l);
 				}
 
-				/* CRC32 was OK. Remove it from skb. */
-				priv->ule_skb->tail -= 4;
-				priv->ule_skb->len -= 4;
-
-				/* Filter on receiver's destination MAC address, if present. */
-				if (!priv->ule_dbit) {
-					/* The destination MAC address is the next data in the skb. */
-					if (memcmp( priv->ule_skb->data, dev->dev_addr, ETH_ALEN )) {
-						/* MAC addresses don't match.  Drop SNDU. */
-						// printk( KERN_WARNING "Dropping SNDU, MAC address.\n" );
-						dev_kfree_skb( priv->ule_skb );
-						goto sndu_done;
-					}
-					if (! priv->ule_bridged) {
-						skb_push( priv->ule_skb, ETH_ALEN + 2 );
-						ethh = (struct ethhdr *)priv->ule_skb->data;
-						memcpy( ethh->h_dest, ethh->h_source, ETH_ALEN );
-						memset( ethh->h_source, 0, ETH_ALEN );
-						ethh->h_proto = htons( priv->ule_sndu_type );
-					} else {
-						/* Skip the Receiver destination MAC address. */
-						skb_pull( priv->ule_skb, ETH_ALEN );
-					}
-				} else {
-					if (! priv->ule_bridged) {
-						skb_push( priv->ule_skb, ETH_HLEN );
-						ethh = (struct ethhdr *)priv->ule_skb->data;
-						memcpy( ethh->h_dest, dev->dev_addr, ETH_ALEN );
-						memset( ethh->h_source, 0, ETH_ALEN );
-						ethh->h_proto = htons( priv->ule_sndu_type );
-					} else {
-						/* skb is in correct state; nothing to do. */
+				/*
+				 * Construct/assure correct ethernet header.
+				 * Note: in bridged mode (priv->ule_bridged !=
+				 * 0) we already have the (original) ethernet
+				 * header at the start of the payload (after
+				 * optional dest. address and any extension
+				 * headers).
+				 */
+
+				if (!priv->ule_bridged) {
+					skb_push(priv->ule_skb, ETH_HLEN);
+					ethh = (struct ethhdr *)priv->ule_skb->data;
+					if (!priv->ule_dbit) {
+						 /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
+						memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
+						memset(ethh->h_source, 0, ETH_ALEN);
 					}
+					else /* zeroize source and dest */
+						memset( ethh, 0, ETH_ALEN*2 );
+
+					ethh->h_proto = htons(priv->ule_sndu_type);
 				}
+				/* else:  skb is in correct state; nothing to do. */
 				priv->ule_bridged = 0;
 
 				/* Stuff into kernel's protocol stack. */
@@ -668,8 +743,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 				 * receive the packet anyhow. */
 				/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
 					priv->ule_skb->pkt_type = PACKET_HOST; */
-				((struct dvb_net_priv *) dev->priv)->stats.rx_packets++;
-				((struct dvb_net_priv *) dev->priv)->stats.rx_bytes += priv->ule_skb->len;
+				priv->stats.rx_packets++;
+				priv->stats.rx_bytes += priv->ule_skb->len;
 				netif_rx(priv->ule_skb);
 			}
 			sndu_done:
@@ -944,7 +1019,7 @@ static int dvb_net_feed_start(struct net_device *dev)
 		dprintk("%s: start filtering\n", __FUNCTION__);
 		priv->secfeed->start_filtering(priv->secfeed);
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
-		struct timespec timeout = { 0, 30000000 }; // 30 msec
+		struct timespec timeout = { 0, 10000000 }; // 10 msec
 
 		/* we have payloads encapsulated in TS */
 		dprintk("%s: alloc tsfeed\n", __FUNCTION__);
@@ -956,10 +1031,13 @@ static int dvb_net_feed_start(struct net_device *dev)
 
 		/* Set netdevice pointer for ts decaps callback. */
 		priv->tsfeed->priv = (void *)dev;
-		ret = priv->tsfeed->set(priv->tsfeed, priv->pid,
-					TS_PACKET, DMX_TS_PES_OTHER,
+		ret = priv->tsfeed->set(priv->tsfeed,
+					priv->pid, /* pid */
+					TS_PACKET, /* type */
+					DMX_TS_PES_OTHER, /* pes type */
 					32768,     /* circular buffer size */
-					timeout);
+					timeout    /* timeout */
+					);
 
 		if (ret < 0) {
 			printk("%s: could not set ts feed\n", dev->name);

+ 3 - 2
drivers/media/dvb/dvb-core/dvbdev.c

@@ -236,7 +236,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 			"dvb/adapter%d/%s%d", adap->num, dnames[type], id);
 
 	class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
-			    NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+			    adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
 
 	dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
 		adap->num, dnames[type], id, nums2minor(adap->num, type, id),
@@ -285,7 +285,7 @@ skip:
 }
 
 
-int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module)
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device)
 {
 	int num;
 
@@ -306,6 +306,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
 	adap->num = num;
 	adap->name = name;
 	adap->module = module;
+	adap->device = device;
 
 	list_add_tail (&adap->list_head, &dvb_adapter_list);
 

+ 3 - 1
drivers/media/dvb/dvb-core/dvbdev.h

@@ -51,6 +51,8 @@ struct dvb_adapter {
 	u8 proposed_mac [6];
 	void* priv;
 
+	struct device *device;
+
 	struct module *module;
 };
 
@@ -76,7 +78,7 @@ struct dvb_device {
 };
 
 
-extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module);
+extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module, struct device *device);
 extern int dvb_unregister_adapter (struct dvb_adapter *adap);
 
 extern int dvb_register_device (struct dvb_adapter *adap,

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

@@ -88,6 +88,7 @@ config DVB_USB_CXUSB
 	select DVB_CX22702
 	select DVB_LGDT330X
 	select DVB_MT352
+	select DVB_ZL10353
 	help
 	  Say Y here to support the Conexant USB2.0 hybrid reference design.
 	  Currently, only DVB and ATSC modes are supported, analog mode
@@ -130,6 +131,15 @@ config DVB_USB_VP702X
 
 	  DVB-S USB2.0 receivers.
 
+config DVB_USB_GP8PSK
+	tristate "GENPIX 8PSK->USB module support"
+	depends on DVB_USB
+	help
+	  Say Y here to support the
+	    GENPIX 8psk module
+
+	  DVB-S USB2.0 receivers.
+
 config DVB_USB_NOVA_T_USB2
 	tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
 	depends on DVB_USB

+ 3 - 0
drivers/media/dvb/dvb-usb/Makefile

@@ -7,6 +7,9 @@ obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
 dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o
 obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
 
+dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o
+obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
+
 dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
 obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
 

+ 29 - 19
drivers/media/dvb/dvb-usb/cxusb.c

@@ -27,8 +27,10 @@
 
 #include "cx22702.h"
 #include "lgdt330x.h"
+#include "lg_h06xf.h"
 #include "mt352.h"
 #include "mt352_priv.h"
+#include "zl10353.h"
 
 /* debug */
 int dvb_usb_cxusb_debug;
@@ -322,32 +324,37 @@ static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
 	return 0;
 }
 
+static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
+					  struct dvb_frontend_parameters *fep)
+{
+	struct dvb_usb_device *d = fe->dvb->priv;
+	return lg_h06xf_pll_set(fe, &d->i2c_adap, fep);
+}
+
 static struct cx22702_config cxusb_cx22702_config = {
 	.demod_address = 0x63,
 
 	.output_mode = CX22702_PARALLEL_OUTPUT,
-
-	.pll_init = dvb_usb_pll_init_i2c,
-	.pll_set  = dvb_usb_pll_set_i2c,
 };
 
 static struct lgdt330x_config cxusb_lgdt3303_config = {
 	.demod_address = 0x0e,
 	.demod_chip    = LGDT3303,
-	.pll_set       = dvb_usb_pll_set_i2c,
 };
 
 static struct mt352_config cxusb_dee1601_config = {
 	.demod_address = 0x0f,
 	.demod_init    = cxusb_dee1601_demod_init,
-	.pll_set       = dvb_usb_pll_set,
 };
 
-struct mt352_config cxusb_mt352_config = {
+static struct zl10353_config cxusb_zl10353_dee1601_config = {
+	.demod_address = 0x0f,
+};
+
+static struct mt352_config cxusb_mt352_config = {
 	/* used in both lgz201 and th7579 */
 	.demod_address = 0x0f,
 	.demod_init    = cxusb_mt352_demod_init,
-	.pll_set       = dvb_usb_pll_set,
 };
 
 /* Callbacks for DVB USB */
@@ -357,17 +364,10 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
 	d->pll_addr = 0x61;
 	memcpy(d->pll_init, bpll, 4);
 	d->pll_desc = &dvb_pll_fmd1216me;
-	return 0;
-}
 
-static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
-{
-	u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
-	/* bpll[2] : unset bit 3, set bits 4&5
-	   bpll[3] : 0x50 - digital, 0x20 - analog */
-	d->pll_addr = 0x61;
-	memcpy(d->pll_init, bpll, 4);
-	d->pll_desc = &dvb_pll_tdvs_tua6034;
+	d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+	d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
 	return 0;
 }
 
@@ -375,6 +375,7 @@ static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
 {
 	d->pll_addr = 0x61;
 	d->pll_desc = &dvb_pll_thomson_dtt7579;
+	d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
 	return 0;
 }
 
@@ -382,6 +383,7 @@ static int cxusb_lgz201_tuner_attach(struct dvb_usb_device *d)
 {
 	d->pll_addr = 0x61;
 	d->pll_desc = &dvb_pll_lg_z201;
+	d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
 	return 0;
 }
 
@@ -389,6 +391,13 @@ static int cxusb_dtt7579_tuner_attach(struct dvb_usb_device *d)
 {
 	d->pll_addr = 0x60;
 	d->pll_desc = &dvb_pll_thomson_dtt7579;
+	d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+	return 0;
+}
+
+static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d)
+{
+	d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
 	return 0;
 }
 
@@ -439,7 +448,8 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
 
 	cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
 
-	if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+	if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
+	    ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
 		return 0;
 
 	return -EIO;
@@ -555,7 +565,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
 	.streaming_ctrl   = cxusb_streaming_ctrl,
 	.power_ctrl       = cxusb_bluebird_power_ctrl,
 	.frontend_attach  = cxusb_lgdt3303_frontend_attach,
-	.tuner_attach     = cxusb_lgh064f_tuner_attach,
+	.tuner_attach     = cxusb_lgdt3303_tuner_attach,
 
 	.i2c_algo         = &cxusb_i2c_algo,
 

+ 6 - 3
drivers/media/dvb/dvb-usb/dibusb-common.c

@@ -173,11 +173,10 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
 	struct dib3000_config demod_cfg;
 	struct dibusb_state *st = d->priv;
 
-	demod_cfg.pll_set = dvb_usb_pll_set_i2c;
-	demod_cfg.pll_init = dvb_usb_pll_init_i2c;
-
 	for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
 		if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
+			d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+			d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
 			d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
 			return 0;
 		}
@@ -190,6 +189,10 @@ int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d)
 {
 	d->pll_addr = 0x60;
 	d->pll_desc = &dvb_pll_env57h1xd5;
+
+	d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+	d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
 	return 0;
 }
 EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);

+ 4 - 3
drivers/media/dvb/dvb-usb/dibusb-mb.c

@@ -20,11 +20,12 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
 	struct dibusb_state *st = d->priv;
 
 	demod_cfg.demod_address = 0x8;
-	demod_cfg.pll_set = dvb_usb_pll_set_i2c;
-	demod_cfg.pll_init = dvb_usb_pll_init_i2c;
 
-	if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
+	if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) {
+		d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+		d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
 		return -ENODEV;
+	}
 
 	d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
 

+ 9 - 6
drivers/media/dvb/dvb-usb/digitv.c

@@ -112,27 +112,30 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe)
 
 static struct mt352_config digitv_mt352_config = {
 	.demod_init = digitv_mt352_demod_init,
-	.pll_set = dvb_usb_pll_set,
 };
 
-static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
 	struct dvb_usb_device *d = fe->dvb->priv;
 	u8 b[5];
-	dvb_usb_pll_set(fe,fep,b);
+	dvb_usb_tuner_calc_regs(fe,fep,b, 5);
 	return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0);
 }
 
 static struct nxt6000_config digitv_nxt6000_config = {
 	.clock_inversion = 1,
-	.pll_set = digitv_nxt6000_pll_set,
 };
 
 static int digitv_frontend_attach(struct dvb_usb_device *d)
 {
-	if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL ||
-		(d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL)
+	if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) {
+		d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
 		return 0;
+	}
+	if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
+		d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+		return 0;
+	}
 	return -EIO;
 }
 

+ 2 - 6
drivers/media/dvb/dvb-usb/dtt200u-fe.c

@@ -18,7 +18,6 @@ struct dtt200u_fe_state {
 
 	struct dvb_frontend_parameters fep;
 	struct dvb_frontend frontend;
-	struct dvb_frontend_ops ops;
 };
 
 static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
@@ -163,16 +162,13 @@ struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
 	deb_info("attaching frontend dtt200u\n");
 
 	state->d = d;
-	memcpy(&state->ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
 
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
-	goto success;
+	return &state->frontend;
 error:
 	return NULL;
-success:
-	return &state->frontend;
 }
 
 static struct dvb_frontend_ops dtt200u_fe_ops = {

+ 8 - 9
drivers/media/dvb/dvb-usb/dvb-usb-dvb.c

@@ -82,7 +82,7 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d)
 	int ret;
 
 	if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
-			d->owner)) < 0) {
+			d->owner, &d->udev->dev)) < 0) {
 		deb_info("dvb_register_adapter failed: error %d", ret);
 		goto err;
 	}
@@ -121,16 +121,15 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d)
 
 	dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
 
-	goto success;
+	d->state |= DVB_USB_STATE_DVB;
+	return 0;
+
 err_dmx_dev:
 	dvb_dmx_release(&d->demux);
 err_dmx:
 	dvb_unregister_adapter(&d->dvb_adap);
 err:
 	return ret;
-success:
-	d->state |= DVB_USB_STATE_DVB;
-	return 0;
 }
 
 int dvb_usb_dvb_exit(struct dvb_usb_device *d)
@@ -184,13 +183,13 @@ int dvb_usb_fe_init(struct dvb_usb_device* d)
 
 	/* re-assign sleep and wakeup functions */
 	if (d->fe != NULL) {
-		d->fe_init = d->fe->ops->init;   d->fe->ops->init  = dvb_usb_fe_wakeup;
-		d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep;
+		d->fe_init = d->fe->ops.init;   d->fe->ops.init  = dvb_usb_fe_wakeup;
+		d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep;
 
 		if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
 			err("Frontend registration failed.");
-			if (d->fe->ops->release)
-				d->fe->ops->release(d->fe);
+			if (d->fe->ops.release)
+				d->fe->ops.release(d->fe);
 			d->fe = NULL;
 			return -ENODEV;
 		}

+ 15 - 9
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c

@@ -46,7 +46,7 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d)
 	return 0;
 }
 
-int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
+int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
 {
 	struct dvb_usb_device *d = fe->dvb->priv;
 	struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
@@ -63,6 +63,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
 	deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
 			d->pll_init[2],d->pll_init[3]);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
 		err("tuner i2c write failed for pll_init.");
 		ret = -EREMOTEIO;
@@ -73,38 +75,42 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
 		d->tuner_pass_ctrl(fe,0,d->pll_addr);
 	return ret;
 }
-EXPORT_SYMBOL(dvb_usb_pll_init_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
 
-int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5])
+int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
 {
 	struct dvb_usb_device *d = fe->dvb->priv;
 
+	if (buf_len != 5)
+		return -EINVAL;
 	if (d->pll_desc == NULL)
 		return 0;
 
 	deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
 
-	b[0] = d->pll_addr << 1;
+	b[0] = d->pll_addr;
 	dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
 
 	deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
 
-	return 0;
+	return 5;
 }
-EXPORT_SYMBOL(dvb_usb_pll_set);
+EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
 
-int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
 	struct dvb_usb_device *d = fe->dvb->priv;
 	int ret = 0;
 	u8 b[5];
 	struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
 
-	dvb_usb_pll_set(fe,fep,b);
+	dvb_usb_tuner_calc_regs(fe,fep,b,5);
 
 	if (d->tuner_pass_ctrl)
 		d->tuner_pass_ctrl(fe,1,d->pll_addr);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
 		err("tuner i2c write failed for pll_set.");
 		ret = -EREMOTEIO;
@@ -116,4 +122,4 @@ int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters
 
 	return ret;
 }
-EXPORT_SYMBOL(dvb_usb_pll_set_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);

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

@@ -31,6 +31,7 @@
 #define USB_VID_VISIONPLUS					0x13d3
 #define USB_VID_TWINHAN						0x1822
 #define USB_VID_ULTIMA_ELECTRONIC			0x05d8
+#define USB_VID_GENPIX					0x09c0
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
@@ -104,5 +105,6 @@
 #define USB_PID_KYE_DVB_T_WARM				0x701f
 #define USB_PID_PCTV_200E					0x020e
 #define USB_PID_PCTV_400E					0x020f
-
+#define USB_PID_GENPIX_8PSK_COLD				0x0200
+#define USB_PID_GENPIX_8PSK_WARM				0x0201
 #endif

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

@@ -330,9 +330,9 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
 extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
 
 /* commonly used pll init and set functions */
-extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
-extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
+extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
+extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
+extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
 
 /* commonly used firmware download types and function */
 struct hexline {

+ 272 - 0
drivers/media/dvb/dvb-usb/gp8psk-fe.c

@@ -0,0 +1,272 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *	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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+struct gp8psk_fe_state {
+	struct dvb_frontend fe;
+
+	struct dvb_usb_device *d;
+
+	u16 snr;
+
+	unsigned long next_snr_check;
+};
+
+static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	u8 lock;
+
+	if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
+		return -EINVAL;
+
+	if (lock)
+		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
+	else
+		*status = 0;
+
+	return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+	(void) fe;
+	*ber = 0;
+	return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+	(void) fe;
+	*unc = 0;
+	return 0;
+}
+
+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;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+	return gp8psk_fe_read_snr(fe, strength);
+}
+
+static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 800;
+	return 0;
+}
+
+static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	struct gp8psk_fe_state *state = fe->demodulator_priv;
+	u8 cmd[10];
+	u32 freq = fep->frequency * 1000;
+
+	cmd[4] = freq         & 0xff;
+	cmd[5] = (freq >> 8)  & 0xff;
+	cmd[6] = (freq >> 16) & 0xff;
+	cmd[7] = (freq >> 24) & 0xff;
+
+	switch(fe->ops.info.type) {
+	case FE_QPSK:
+		cmd[0] =  fep->u.qpsk.symbol_rate        & 0xff;
+		cmd[1] = (fep->u.qpsk.symbol_rate >>  8) & 0xff;
+		cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
+		cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
+		cmd[8] = ADV_MOD_DVB_QPSK;
+		cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+		break;
+	default:
+		// other modes are unsuported right now
+		cmd[0] = 0;
+		cmd[1] = 0;
+		cmd[2] = 0;
+		cmd[3] = 0;
+		cmd[8] = 0;
+		cmd[9] = 0;
+		break;
+	}
+
+	gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+
+	state->next_snr_check = jiffies;
+
+	return 0;
+}
+
+static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	return 0;
+}
+
+
+static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+	deb_fe("%s\n",__FUNCTION__);
+
+	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
+			m->msg, m->msg_len)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
+				    fe_sec_mini_cmd_t burst)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	u8 cmd;
+
+	deb_fe("%s\n",__FUNCTION__);
+
+	/* These commands are certainly wrong */
+	cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
+
+	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
+			&cmd, 0)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+	if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
+		 (tone == SEC_TONE_ON), 0, NULL, 0)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
+			 voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
+		return -EINVAL;
+	}
+	return 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;
+	u8 cmd = sw_cmd & 0x7f;
+
+	if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
+			NULL, 0)) {
+		return -EINVAL;
+	}
+	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
+			0, NULL, 0)) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void gp8psk_fe_release(struct dvb_frontend* fe)
+{
+	struct gp8psk_fe_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops gp8psk_fe_ops;
+
+struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
+{
+	struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
+	if (s == NULL)
+		goto error;
+
+	s->d = d;
+	memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
+	s->fe.demodulator_priv = s;
+
+	goto success;
+error:
+	return NULL;
+success:
+	return &s->fe;
+}
+
+
+static struct dvb_frontend_ops gp8psk_fe_ops = {
+	.info = {
+		.name			= "Genpix 8psk-USB DVB-S",
+		.type			= FE_QPSK,
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 100,
+		.symbol_rate_min        = 1000000,
+		.symbol_rate_max        = 45000000,
+		.symbol_rate_tolerance  = 500,  /* ppm */
+		.caps = FE_CAN_INVERSION_AUTO |
+				FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+				FE_CAN_QPSK
+	},
+
+	.release = gp8psk_fe_release,
+
+	.init = NULL,
+	.sleep = NULL,
+
+	.set_frontend = gp8psk_fe_set_frontend,
+	.get_frontend = gp8psk_fe_get_frontend,
+	.get_tune_settings = gp8psk_fe_get_tune_settings,
+
+	.read_status = gp8psk_fe_read_status,
+	.read_ber = gp8psk_fe_read_ber,
+	.read_signal_strength = gp8psk_fe_read_signal_strength,
+	.read_snr = gp8psk_fe_read_snr,
+	.read_ucblocks = gp8psk_fe_read_unc_blocks,
+
+	.diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
+	.diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
+	.set_tone = gp8psk_fe_set_tone,
+	.set_voltage = gp8psk_fe_set_voltage,
+	.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+};

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

@@ -0,0 +1,256 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *	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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+/* debug */
+static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
+int dvb_usb_gp8psk_debug;
+module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+	int ret = 0,try = 0;
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	while (ret >= 0 && ret != blen && try < 3) {
+		ret = usb_control_msg(d->udev,
+			usb_rcvctrlpipe(d->udev,0),
+			req,
+			USB_TYPE_VENDOR | USB_DIR_IN,
+			value,index,b,blen,
+			2000);
+		deb_info("reading number %d (ret: %d)\n",try,ret);
+		try++;
+	}
+
+	if (ret < 0 || ret != blen) {
+		warn("usb in operation failed.");
+		ret = -EIO;
+	} else
+		ret = 0;
+
+	deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+	debug_dump(b,blen,deb_xfer);
+
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+			     u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+	debug_dump(b,blen,deb_xfer);
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	if (usb_control_msg(d->udev,
+			usb_sndctrlpipe(d->udev,0),
+			req,
+			USB_TYPE_VENDOR | USB_DIR_OUT,
+			value,index,b,blen,
+			2000) != blen) {
+		warn("usb out operation failed.");
+		ret = -EIO;
+	} else
+		ret = 0;
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
+{
+	int ret;
+	const struct firmware *fw = NULL;
+	u8 *ptr, *buf;
+	if ((ret = request_firmware(&fw, bcm4500_firmware,
+					&d->udev->dev)) != 0) {
+		err("did not find the bcm4500 firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+			bcm4500_firmware,ret);
+		return ret;
+	}
+
+	ret = -EINVAL;
+
+	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);
+
+	ptr = fw->data;
+	buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+
+	while (ptr[0] != 0xff) {
+		u16 buflen = ptr[0] + 4;
+		if (ptr + buflen >= fw->data + fw->size) {
+			err("failed to load bcm4500 firmware.");
+			goto out_free;
+		}
+		memcpy(buf, ptr, buflen);
+		if (dvb_usb_generic_write(d, buf, buflen)) {
+			err("failed to load bcm4500 firmware.");
+			goto out_free;
+		}
+		ptr += buflen;
+	}
+
+	ret = 0;
+
+out_free:
+	kfree(buf);
+out_rel_fw:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 status, buf;
+	if (onoff) {
+		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+		if (! (status & 0x01))  /* started */
+			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 (! (status & 0x04)) /* 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);
+	} else {
+		/* Turn off LNB power */
+		if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
+			return EINVAL;
+		/* Turn off 8psk power */
+		if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+			return -EINVAL;
+
+	}
+	return 0;
+}
+
+
+static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0);
+}
+
+static int gp8psk_frontend_attach(struct dvb_usb_device *d)
+{
+	d->fe = gp8psk_fe_attach(d);
+
+	return 0;
+}
+
+static struct dvb_usb_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);
+}
+
+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) },
+	    { 0 },
+};
+MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
+
+static struct dvb_usb_properties gp8psk_properties = {
+	.caps = 0,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-gp8psk-01.fw",
+
+	.streaming_ctrl   = gp8psk_streaming_ctrl,
+	.power_ctrl       = gp8psk_power_ctrl,
+	.frontend_attach  = gp8psk_frontend_attach,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	/* parameter for the MPEG2-data transfer */
+	.urb = {
+		.type = DVB_USB_BULK,
+		.count = 7,
+		.endpoint = 0x82,
+		.u = {
+			.bulk = {
+				.buffersize = 8192,
+			}
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+		  .cold_ids = { &gp8psk_usb_table[0], NULL },
+		  .warm_ids = { &gp8psk_usb_table[1], NULL },
+		},
+		{ 0 },
+	}
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gp8psk_usb_driver = {
+	.name		= "dvb_usb_gp8psk",
+	.probe		= gp8psk_usb_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= gp8psk_usb_table,
+};
+
+/* module stuff */
+static int __init gp8psk_usb_module_init(void)
+{
+	int result;
+	if ((result = usb_register(&gp8psk_usb_driver))) {
+		err("usb_register failed. (%d)",result);
+		return result;
+	}
+
+	return 0;
+}
+
+static void __exit gp8psk_usb_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&gp8psk_usb_driver);
+}
+
+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_LICENSE("GPL");

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

@@ -0,0 +1,79 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *	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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_GP8PSK_H_
+#define _DVB_USB_GP8PSK_H_
+
+#define DVB_USB_LOG_PREFIX "gp8psk"
+#include "dvb-usb.h"
+
+extern int dvb_usb_gp8psk_debug;
+#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_gp8psk_debug,0x04,args)
+#define deb_fe(args...)   dprintk(dvb_usb_gp8psk_debug,0x08,args)
+/* gp8psk commands */
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN                     0xC0
+#define TH_COMMAND_OUT                    0xC1
+
+/* command bytes */
+#define GET_8PSK_CONFIG                 0x80
+#define SET_8PSK_CONFIG                 0x81
+#define ARM_TRANSFER                    0x85
+#define TUNE_8PSK                       0x86
+#define GET_SIGNAL_STRENGTH             0x87
+#define LOAD_BCM4500                    0x88
+#define BOOT_8PSK                       0x89
+#define START_INTERSIL                  0x8A
+#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
+
+/* Satellite modulation modes */
+#define ADV_MOD_DVB_QPSK 0     /* DVB-S QPSK */
+#define ADV_MOD_TURBO_QPSK 1   /* Turbo QPSK */
+#define ADV_MOD_TURBO_8PSK 2   /* Turbo 8PSK (also used for Trellis 8PSK) */
+#define ADV_MOD_TURBO_16QAM 3  /* Turbo 16QAM (also used for Trellis 8PSK) */
+
+#define ADV_MOD_DCII_C_QPSK 4  /* Digicipher II Combo */
+#define ADV_MOD_DCII_I_QPSK 5  /* Digicipher II I-stream */
+#define ADV_MOD_DCII_Q_QPSK 6  /* Digicipher II Q-stream */
+#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
+#define ADV_MOD_DSS_QPSK 8     /* DSS (DIRECTV) QPSK */
+#define ADV_MOD_DVB_BPSK 9     /* DVB-S BPSK */
+
+#define GET_USB_SPEED                     0x07
+ #define USB_SPEED_LOW                    0
+ #define USB_SPEED_FULL                   1
+ #define USB_SPEED_HIGH                   2
+
+#define RESET_FX2                         0x13
+
+#define FW_VERSION_READ                   0x0B
+#define VENDOR_STRING_READ                0x0C
+#define PRODUCT_STRING_READ               0x0D
+#define FW_BCD_VERSION_READ               0x14
+
+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);
+
+#endif

+ 1 - 1
drivers/media/dvb/dvb-usb/umt-010.c

@@ -57,7 +57,6 @@ static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
 	memset(&umt_config,0,sizeof(struct mt352_config));
 	umt_config.demod_init = umt_mt352_demod_init;
 	umt_config.demod_address = 0xf;
-	umt_config.pll_set = dvb_usb_pll_set;
 
 	d->fe = mt352_attach(&umt_config, &d->i2c_adap);
 
@@ -68,6 +67,7 @@ static int umt_tuner_attach (struct dvb_usb_device *d)
 {
 	d->pll_addr = 0x61;
 	d->pll_desc = &dvb_pll_tua6034;
+	d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
 	return 0;
 }
 

+ 3 - 4
drivers/media/dvb/dvb-usb/vp702x-fe.c

@@ -287,17 +287,16 @@ struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
 		goto error;
 
 	s->d = d;
-	s->fe.ops = &vp702x_fe_ops;
+
+	memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
 	s->fe.demodulator_priv = s;
 
 	s->lnb_buf[1] = SET_LNB_POWER;
 	s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
 
-	goto success;
+	return &s->fe;
 error:
 	return NULL;
-success:
-	return &s->fe;
 }
 
 

+ 2 - 7
drivers/media/dvb/dvb-usb/vp7045-fe.c

@@ -23,8 +23,6 @@
 
 struct vp7045_fe_state {
 	struct dvb_frontend fe;
-	struct dvb_frontend_ops ops;
-
 	struct dvb_usb_device *d;
 };
 
@@ -151,15 +149,12 @@ struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
 		goto error;
 
 	s->d = d;
-	memcpy(&s->ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
-	s->fe.ops = &s->ops;
+	memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
 	s->fe.demodulator_priv = s;
 
-	goto success;
+	return &s->fe;
 error:
 	return NULL;
-success:
-	return &s->fe;
 }
 
 

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

@@ -157,7 +157,7 @@ config DVB_STV0297
 	help
 	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
-comment "ATSC (North American/Korean Terresterial DTV) frontends"
+comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
 	depends on DVB_CORE
 
 config DVB_NXT200X
@@ -216,4 +216,20 @@ config DVB_LGDT330X
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
 	  to support this frontend.
 
+
+comment "Miscellaneous devices"
+	depends on DVB_CORE
+
+config DVB_LNBP21
+	tristate "LNBP21 SEC controller"
+	depends on DVB_CORE
+	help
+	  An SEC control chip.
+
+config DVB_ISL6421
+	tristate "ISL6421 SEC controller"
+	depends on DVB_CORE
+	help
+	  An SEC control chip.
+
 endmenu

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

@@ -31,3 +31,5 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_ISL6421) += isl6421.o

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

@@ -48,7 +48,6 @@
 struct bcm3510_state {
 
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct bcm3510_config* config;
 	struct dvb_frontend frontend;
 
@@ -791,10 +790,9 @@ struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
 
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
 	mutex_init(&state->hab_mutex);

+ 4 - 2
drivers/media/dvb/frontends/bsbe1.h

@@ -89,12 +89,13 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra
 	return 0;
 }
 
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	int ret;
 	u8 data[4];
 	u32 div;
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+	struct i2c_adapter *i2c = fe->tuner_priv;
 
 	if ((params->frequency < 950000) || (params->frequency > 2150000))
 		return -EINVAL;
@@ -105,6 +106,8 @@ static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c,
 	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
 	data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	ret = i2c_transfer(i2c, &msg, 1);
 	return (ret != 1) ? -EIO : 0;
 }
@@ -117,7 +120,6 @@ static struct stv0299_config alps_bsbe1_config = {
 	.skip_reinit = 0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = alps_bsbe1_set_symbol_rate,
-	.pll_set = alps_bsbe1_pll_set,
 };
 
 #endif

+ 4 - 2
drivers/media/dvb/frontends/bsru6.h

@@ -101,11 +101,12 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra
 	return 0;
 }
 
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	u8 buf[4];
 	u32 div;
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	struct i2c_adapter *i2c = fe->tuner_priv;
 
 	if ((params->frequency < 950000) || (params->frequency > 2150000))
 		return -EINVAL;
@@ -119,6 +120,8 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c,
 	if (params->frequency > 1530000)
 		buf[3] = 0xc0;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(i2c, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -134,7 +137,6 @@ static struct stv0299_config alps_bsru6_config = {
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 100,
 	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-	.pll_set = alps_bsru6_pll_set,
 };
 
 #endif

+ 18 - 13
drivers/media/dvb/frontends/cx22700.c

@@ -34,8 +34,6 @@ struct cx22700_state {
 
 	struct i2c_adapter* i2c;
 
-	struct dvb_frontend_ops ops;
-
 	const struct cx22700_config* config;
 
 	struct dvb_frontend frontend;
@@ -247,12 +245,6 @@ static int cx22700_init (struct dvb_frontend* fe)
 
 	cx22700_writereg (state, 0x00, 0x01);
 
-	if (state->config->pll_init) {
-		cx22700_writereg (state, 0x0a, 0x00);  /* open i2c bus switch */
-		state->config->pll_init(fe);
-		cx22700_writereg (state, 0x0a, 0x01);  /* close i2c bus switch */
-	}
-
 	return 0;
 }
 
@@ -333,9 +325,11 @@ static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
 	cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
 	cx22700_writereg (state, 0x00, 0x00);
 
-	cx22700_writereg (state, 0x0a, 0x00);  /* open i2c bus switch */
-	state->config->pll_set(fe, p);
-	cx22700_writereg (state, 0x0a, 0x01);  /* close i2c bus switch */
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
 	cx22700_set_inversion (state, p->inversion);
 	cx22700_set_tps (state, &p->u.ofdm);
 	cx22700_writereg (state, 0x37, 0x01);  /* PAL loop filter off */
@@ -353,6 +347,17 @@ static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
 	return cx22700_get_tps (state, &p->u.ofdm);
 }
 
+static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct cx22700_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return cx22700_writereg(state, 0x0a, 0x00);
+	} else {
+		return cx22700_writereg(state, 0x0a, 0x01);
+	}
+}
+
 static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
 	fesettings->min_delay_ms = 150;
@@ -381,13 +386,12 @@ struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check if the demod is there */
 	if (cx22700_readreg(state, 0x07) < 0) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -413,6 +417,7 @@ static struct dvb_frontend_ops cx22700_ops = {
 	.release = cx22700_release,
 
 	.init = cx22700_init,
+	.i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
 
 	.set_frontend = cx22700_set_frontend,
 	.get_frontend = cx22700_get_frontend,

+ 0 - 4
drivers/media/dvb/frontends/cx22700.h

@@ -29,10 +29,6 @@ struct cx22700_config
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,

+ 5 - 24
drivers/media/dvb/frontends/cx22702.c

@@ -40,8 +40,6 @@ struct cx22702_state {
 
 	struct i2c_adapter* i2c;
 
-	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct cx22702_config* config;
 
@@ -211,22 +209,10 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
 	u8 val;
 	struct cx22702_state* state = fe->demodulator_priv;
 
-	/* set PLL */
-	cx22702_i2c_gate_ctrl(fe, 1);
-	if (state->config->pll_set) {
-		state->config->pll_set(fe, p);
-	} else if (state->config->pll_desc) {
-		u8 pllbuf[4];
-		struct i2c_msg msg = { .addr = state->config->pll_address,
-				       .buf = pllbuf, .len = 4 };
-		dvb_pll_configure(state->config->pll_desc, pllbuf,
-				  p->frequency,
-				  p->u.ofdm.bandwidth);
-		i2c_transfer(state->i2c, &msg, 1);
-	} else {
-		BUG();
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 	}
-	cx22702_i2c_gate_ctrl(fe, 0);
 
 	/* set inversion */
 	cx22702_set_inversion (state, p->inversion);
@@ -358,10 +344,6 @@ static int cx22702_init (struct dvb_frontend* fe)
 
 	cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
 
-	/* init PLL */
-	if (state->config->pll_init)
-		state->config->pll_init(fe);
-
 	cx22702_i2c_gate_ctrl(fe, 0);
 
 	return 0;
@@ -495,7 +477,6 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
 	state->prevUCBlocks = 0;
 
 	/* check if the demod is there */
@@ -503,7 +484,7 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
 		goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -530,6 +511,7 @@ static struct dvb_frontend_ops cx22702_ops = {
 	.release = cx22702_release,
 
 	.init = cx22702_init,
+	.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
 
 	.set_frontend = cx22702_set_tps,
 	.get_frontend = cx22702_get_frontend,
@@ -540,7 +522,6 @@ static struct dvb_frontend_ops cx22702_ops = {
 	.read_signal_strength = cx22702_read_signal_strength,
 	.read_snr = cx22702_read_snr,
 	.read_ucblocks = cx22702_read_ucblocks,
-	.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
 };
 
 module_param(debug, int, 0644);

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

@@ -39,13 +39,6 @@ struct cx22702_config
 #define CX22702_PARALLEL_OUTPUT 0
 #define CX22702_SERIAL_OUTPUT   1
 	u8 output_mode;
-
-	/* PLL maintenance */
-	u8 pll_address;
-	struct dvb_pll_desc *pll_desc;
-
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,

+ 8 - 18
drivers/media/dvb/frontends/cx24110.c

@@ -36,8 +36,6 @@ struct cx24110_state {
 
 	struct i2c_adapter* i2c;
 
-	struct dvb_frontend_ops ops;
-
 	const struct cx24110_config* config;
 
 	struct dvb_frontend frontend;
@@ -250,7 +248,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
 	static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
 	int i;
 
-dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
+	dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
 	if (srate>90999000UL/2)
 		srate=90999000UL/2;
 	if (srate<500000)
@@ -366,17 +364,6 @@ static int cx24110_initfe(struct dvb_frontend* fe)
 		cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
 	};
 
-	if (state->config->pll_init) state->config->pll_init(fe);
-
-	return 0;
-}
-
-static int cx24110_sleep(struct dvb_frontend *fe)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-	if (state->config->pll_sleep)
-		  return state->config->pll_sleep(fe);
 	return 0;
 }
 
@@ -548,7 +535,12 @@ static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
 {
 	struct cx24110_state *state = fe->demodulator_priv;
 
-	state->config->pll_set(fe, p);
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
 	cx24110_set_inversion (state, p->inversion);
 	cx24110_set_fec (state, p->u.qpsk.fec_inner);
 	cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -612,7 +604,6 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
 	state->lastber = 0;
 	state->lastbler = 0;
 	state->lastesn0 = 0;
@@ -622,7 +613,7 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
 	if ((ret != 0x5a) && (ret != 0x69)) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -651,7 +642,6 @@ static struct dvb_frontend_ops cx24110_ops = {
 	.release = cx24110_release,
 
 	.init = cx24110_initfe,
-	.sleep = cx24110_sleep,
 	.set_frontend = cx24110_set_frontend,
 	.get_frontend = cx24110_get_frontend,
 	.read_status = cx24110_read_status,

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

@@ -31,11 +31,6 @@ struct cx24110_config
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-	int (*pll_sleep)(struct dvb_frontend* fe);
 };
 
 extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,

+ 51 - 144
drivers/media/dvb/frontends/cx24123.c

@@ -41,14 +41,12 @@ static int debug;
 struct cx24123_state
 {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct cx24123_config* config;
 
 	struct dvb_frontend frontend;
 
 	u32 lastber;
 	u16 snr;
-	u8  lnbreg;
 
 	/* Some PLL specifics for tuning */
 	u32 VCAarg;
@@ -249,29 +247,6 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
 	return 0;
 }
 
-static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
-{
-	u8 buf[] = { reg, data };
-	/* fixme: put the intersil addr int the config */
-	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
-	int err;
-
-	if (debug>1)
-		printk("cx24123: %s:  writeln addr=0x08, reg 0x%02x, value 0x%02x\n",
-						__FUNCTION__,reg, data);
-
-	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-		printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
-			 " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
-		return -EREMOTEIO;
-	}
-
-	/* cache the write, no way to read back */
-	state->lnbreg = data;
-
-	return 0;
-}
-
 static int cx24123_readreg(struct cx24123_state* state, u8 reg)
 {
 	int ret;
@@ -295,11 +270,6 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg)
 	return b1[0];
 }
 
-static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
-{
-	return state->lnbreg;
-}
-
 static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
 {
 	u8 nom_reg = cx24123_readreg(state, 0x0e);
@@ -458,8 +428,8 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
 	u8 pll_mult;
 
 	/*  check if symbol rate is within limits */
-	if ((srate > state->ops.info.symbol_rate_max) ||
-	    (srate < state->ops.info.symbol_rate_min))
+	if ((srate > state->frontend.ops.info.symbol_rate_max) ||
+	    (srate < state->frontend.ops.info.symbol_rate_min))
 		return -EOPNOTSUPP;;
 
 	/* choose the sampling rate high enough for the required operation,
@@ -687,13 +657,6 @@ static int cx24123_initfe(struct dvb_frontend* fe)
 	for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
 		cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
 
-	if (state->config->pll_init)
-		state->config->pll_init(fe);
-
-	/* Configure the LNB for 14V */
-	if (state->config->use_isl6421)
-		cx24123_writelnbreg(state, 0x0, 0x2a);
-
 	return 0;
 }
 
@@ -702,50 +665,18 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
 	struct cx24123_state *state = fe->demodulator_priv;
 	u8 val;
 
-	switch (state->config->use_isl6421) {
-
-	case 1:
+	val = cx24123_readreg(state, 0x29) & ~0x40;
 
-		val = cx24123_readlnbreg(state, 0x0);
-
-		switch (voltage) {
-		case SEC_VOLTAGE_13:
-			dprintk("%s:  isl6421 voltage = 13V\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
-		case SEC_VOLTAGE_18:
-			dprintk("%s:  isl6421 voltage = 18V\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
-		case SEC_VOLTAGE_OFF:
-			dprintk("%s:  isl5421 voltage off\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val & 0x30);
-		default:
-			return -EINVAL;
-		};
-
-	case 0:
-
-		val = cx24123_readreg(state, 0x29);
-
-		switch (voltage) {
-		case SEC_VOLTAGE_13:
-			dprintk("%s: setting voltage 13V\n", __FUNCTION__);
-			if (state->config->enable_lnb_voltage)
-				state->config->enable_lnb_voltage(fe, 1);
-			return cx24123_writereg(state, 0x29, val | 0x80);
-		case SEC_VOLTAGE_18:
-			dprintk("%s: setting voltage 18V\n", __FUNCTION__);
-			if (state->config->enable_lnb_voltage)
-				state->config->enable_lnb_voltage(fe, 1);
-			return cx24123_writereg(state, 0x29, val & 0x7f);
-		case SEC_VOLTAGE_OFF:
-			dprintk("%s: setting voltage off\n", __FUNCTION__);
-			if (state->config->enable_lnb_voltage)
-				state->config->enable_lnb_voltage(fe, 0);
-			return 0;
-		default:
-			return -EINVAL;
-		};
-	}
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+		return cx24123_writereg(state, 0x29, val | 0x80);
+	case SEC_VOLTAGE_18:
+		dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+		return cx24123_writereg(state, 0x29, val & 0x7f);
+	default:
+		return -EINVAL;
+	};
 
 	return 0;
 }
@@ -766,27 +697,20 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
 static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
-	int i, val;
+	int i, val, tone;
 
 	dprintk("%s:\n",__FUNCTION__);
 
-	/* check if continuous tone has been stopped */
-	if (state->config->use_isl6421)
-		val = cx24123_readlnbreg(state, 0x00) & 0x10;
-	else
-		val = cx24123_readreg(state, 0x29) & 0x10;
-
-
-	if (val) {
-		printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
-		return -ENOTSUPP;
-	}
+	/* stop continuous tone if enabled */
+	tone = cx24123_readreg(state, 0x29);
+	if (tone & 0x10)
+		cx24123_writereg(state, 0x29, tone & ~0x50);
 
 	/* wait for diseqc queue ready */
 	cx24123_wait_for_diseqc(state);
 
 	/* select tone mode */
-	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8);
+	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
 
 	for (i = 0; i < cmd->msg_len; i++)
 		cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
@@ -797,36 +721,33 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
 	/* wait for diseqc message to finish sending */
 	cx24123_wait_for_diseqc(state);
 
+	/* restart continuous tone if enabled */
+	if (tone & 0x10) {
+		cx24123_writereg(state, 0x29, tone & ~0x40);
+	}
+
 	return 0;
 }
 
 static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
-	int val;
+	int val, tone;
 
 	dprintk("%s:\n", __FUNCTION__);
 
-	/* check if continuous tone has been stoped */
-	if (state->config->use_isl6421)
-		val = cx24123_readlnbreg(state, 0x00) & 0x10;
-	else
-		val = cx24123_readreg(state, 0x29) & 0x10;
-
-
-	if (val) {
-		printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
-		return -ENOTSUPP;
-	}
+	/* stop continuous tone if enabled */
+	tone = cx24123_readreg(state, 0x29);
+	if (tone & 0x10)
+		cx24123_writereg(state, 0x29, tone & ~0x50);
 
+	/* wait for diseqc queue ready */
 	cx24123_wait_for_diseqc(state);
 
 	/* select tone mode */
-	val = cx24123_readreg(state, 0x2a) & 0xf8;
-	cx24123_writereg(state, 0x2a, val | 0x04);
-
+	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
+	msleep(30);
 	val = cx24123_readreg(state, 0x29);
-
 	if (burst == SEC_MINI_A)
 		cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
 	else if (burst == SEC_MINI_B)
@@ -835,7 +756,12 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
 		return -EINVAL;
 
 	cx24123_wait_for_diseqc(state);
+	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
 
+	/* restart continuous tone if enabled */
+	if (tone & 0x10) {
+		cx24123_writereg(state, 0x29, tone & ~0x40);
+	}
 	return 0;
 }
 
@@ -976,38 +902,21 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 	struct cx24123_state *state = fe->demodulator_priv;
 	u8 val;
 
-	switch (state->config->use_isl6421) {
-	case 1:
-
-		val = cx24123_readlnbreg(state, 0x0);
-
-		switch (tone) {
-		case SEC_TONE_ON:
-			dprintk("%s:  isl6421 sec tone on\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val | 0x10);
-		case SEC_TONE_OFF:
-			dprintk("%s:  isl6421 sec tone off\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val & 0x2f);
-		default:
-			printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
-			return -EINVAL;
-		}
-
-	case 0:
+	/* wait for diseqc queue ready */
+	cx24123_wait_for_diseqc(state);
 
-		val = cx24123_readreg(state, 0x29);
+	val = cx24123_readreg(state, 0x29) & ~0x40;
 
-		switch (tone) {
-		case SEC_TONE_ON:
-			dprintk("%s: setting tone on\n", __FUNCTION__);
-			return cx24123_writereg(state, 0x29, val | 0x10);
-		case SEC_TONE_OFF:
-			dprintk("%s: setting tone off\n",__FUNCTION__);
-			return cx24123_writereg(state, 0x29, val & 0xef);
-		default:
-			printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
-			return -EINVAL;
-		}
+	switch (tone) {
+	case SEC_TONE_ON:
+		dprintk("%s: setting tone on\n", __FUNCTION__);
+		return cx24123_writereg(state, 0x29, val | 0x10);
+	case SEC_TONE_OFF:
+		dprintk("%s: setting tone off\n",__FUNCTION__);
+		return cx24123_writereg(state, 0x29, val & 0xef);
+	default:
+		printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+		return -EINVAL;
 	}
 
 	return 0;
@@ -1040,10 +949,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
 	state->lastber = 0;
 	state->snr = 0;
-	state->lnbreg = 0;
 	state->VCAarg = 0;
 	state->VGAarg = 0;
 	state->bandselectarg = 0;
@@ -1059,7 +966,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 

+ 0 - 13
drivers/media/dvb/frontends/cx24123.h

@@ -28,21 +28,8 @@ struct cx24123_config
 	/* the demodulator's i2c address */
 	u8 demod_address;
 
-	/*
-	   cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
-	   for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
-	   from register 0x29 of the CX24123 demodulator
-	*/
-	int use_isl6421;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
 	/* Need to set device param for start_dma */
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-
-	void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
 };
 
 extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,

+ 0 - 2
drivers/media/dvb/frontends/dib3000-common.h

@@ -38,8 +38,6 @@
 struct dib3000_state {
 	struct i2c_adapter* i2c;
 
-	struct dvb_frontend_ops ops;
-
 /* configuration settings */
 	struct dib3000_config config;
 

+ 0 - 4
drivers/media/dvb/frontends/dib3000.h

@@ -30,10 +30,6 @@ struct dib3000_config
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance and the i2c address of the PLL */
-	int (*pll_init)(struct dvb_frontend *fe);
-	int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
 };
 
 struct dib_fe_xfer_ops

+ 4 - 7
drivers/media/dvb/frontends/dib3000mb.c

@@ -60,8 +60,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
 	fe_code_rate_t fe_cr = FEC_NONE;
 	int search_state, seq;
 
-	if (tuner && state->config.pll_set) {
-		state->config.pll_set(fe, fep);
+	if (tuner && fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, fep);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 
 		deb_setf("bandwidth: ");
 		switch (ofdm->bandwidth) {
@@ -386,9 +387,6 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
 
 	wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
 
-	if (state->config.pll_init)
-		state->config.pll_init(fe);
-
 	return 0;
 }
 
@@ -707,7 +705,6 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
 	/* setup the state */
 	state->i2c = i2c;
 	memcpy(&state->config,config,sizeof(struct dib3000_config));
-	memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check for the correct demod */
 	if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -717,7 +714,7 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
 		goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
 	/* set the xfer operations */

+ 5 - 9
drivers/media/dvb/frontends/dib3000mc.c

@@ -462,8 +462,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 	int search_state,auto_val;
 	u16 val;
 
-	if (tuner && state->config.pll_set) { /* initial call from dvb */
-		state->config.pll_set(fe,fep);
+	if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
+		fe->ops.tuner_ops.set_params(fe, fep);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 
 		state->last_tuned_freq = fep->frequency;
 	//	if (!scanboost) {
@@ -642,9 +643,6 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
 
 	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
 
-	if (state->config.pll_init)
-		state->config.pll_init(fe);
-
 	deb_info("init end\n");
 	return 0;
 }
@@ -839,7 +837,6 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
 	/* setup the state */
 	state->i2c = i2c;
 	memcpy(&state->config,config,sizeof(struct dib3000_config));
-	memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check for the correct demod */
 	if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -859,7 +856,7 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
 	/* set the xfer operations */
@@ -876,6 +873,7 @@ error:
 	kfree(state);
 	return NULL;
 }
+EXPORT_SYMBOL(dib3000mc_attach);
 
 static struct dvb_frontend_ops dib3000mc_ops = {
 
@@ -914,5 +912,3 @@ static struct dvb_frontend_ops dib3000mc_ops = {
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000mc_attach);

+ 176 - 5
drivers/media/dvb/frontends/dvb-pll.c

@@ -227,10 +227,10 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
 EXPORT_SYMBOL(dvb_pll_tua6034);
 
 /* Infineon TUA6034
- * used in LG TDVS H061F and LG TDVS H062F
+ * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
  */
-struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
-	.name  = "LG/Infineon TUA6034",
+struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+	.name  = "LG TDVS-H06xF",
 	.min   =  54000000,
 	.max   = 863000000,
 	.count = 3,
@@ -240,7 +240,7 @@ struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
 		{  999999999, 44000000, 62500, 0xce, 0x04 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_tdvs_tua6034);
+EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
 
 /* Philips FMD1216ME
  * used in Medion Hybrid PCMCIA card and USB Box
@@ -419,6 +419,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
 };
 EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
 
+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                                                        */
 
@@ -443,7 +456,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 	if (debug)
 		printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
 		       desc->name, freq, bandwidth, i, desc->count);
-	BUG_ON(i == desc->count);
+	if (i == desc->count)
+		return -EINVAL;
 
 	div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
 	buf[0] = div >> 8;
@@ -462,6 +476,163 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 }
 EXPORT_SYMBOL(dvb_pll_configure);
 
+static int dvb_pll_release(struct dvb_frontend *fe)
+{
+	if (fe->tuner_priv)
+		kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int dvb_pll_sleep(struct dvb_frontend *fe)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	u8 buf[4];
+	struct i2c_msg msg =
+		{ .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	int i;
+	int result;
+
+	for (i = 0; i < priv->pll_desc->count; i++) {
+		if (priv->pll_desc->entries[i].limit == 0)
+			break;
+	}
+	if (i == priv->pll_desc->count)
+		return 0;
+
+	buf[0] = 0;
+	buf[1] = 0;
+	buf[2] = priv->pll_desc->entries[i].config;
+	buf[3] = priv->pll_desc->entries[i].cb;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+		return result;
+	}
+
+	return 0;
+}
+
+static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	u8 buf[4];
+	struct i2c_msg msg =
+		{ .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	int result;
+	u32 div;
+	int i;
+	u32 bandwidth = 0;
+
+	if (priv->i2c == NULL)
+		return -EINVAL;
+
+	// DVBT bandwidth only just now
+	if (fe->ops.info.type == FE_OFDM) {
+		bandwidth = params->u.ofdm.bandwidth;
+	}
+
+	if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0)
+		return result;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+		return result;
+	}
+
+	// calculate the frequency we set it to
+	for (i = 0; i < priv->pll_desc->count; i++) {
+		if (params->frequency > priv->pll_desc->entries[i].limit)
+			continue;
+		break;
+	}
+	div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+	priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+	priv->bandwidth = bandwidth;
+
+	return 0;
+}
+
+static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	int result;
+	u32 div;
+	int i;
+	u32 bandwidth = 0;
+
+	if (buf_len < 5)
+		return -EINVAL;
+
+	// DVBT bandwidth only just now
+	if (fe->ops.info.type == FE_OFDM) {
+		bandwidth = params->u.ofdm.bandwidth;
+	}
+
+	if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0)
+		return result;
+	buf[0] = priv->pll_i2c_address;
+
+	// calculate the frequency we set it to
+	for (i = 0; i < priv->pll_desc->count; i++) {
+		if (params->frequency > priv->pll_desc->entries[i].limit)
+			continue;
+		break;
+	}
+	div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+	priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+	priv->bandwidth = bandwidth;
+
+	return 5;
+}
+
+static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static struct dvb_tuner_ops dvb_pll_tuner_ops = {
+	.release = dvb_pll_release,
+	.sleep = dvb_pll_sleep,
+	.set_params = dvb_pll_set_params,
+	.calc_regs = dvb_pll_calc_regs,
+	.get_frequency = dvb_pll_get_frequency,
+	.get_bandwidth = dvb_pll_get_bandwidth,
+};
+
+int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+{
+	struct dvb_pll_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	priv->pll_i2c_address = pll_addr;
+	priv->i2c = i2c;
+	priv->pll_desc = desc;
+
+	memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops));
+	strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
+	fe->ops.tuner_ops.info.frequency_min = desc->min;
+	fe->ops.tuner_ops.info.frequency_min = desc->max;
+
+	fe->tuner_priv = priv;
+	return 0;
+}
+EXPORT_SYMBOL(dvb_pll_attach);
+
 MODULE_DESCRIPTION("dvb pll library");
 MODULE_AUTHOR("Gerd Knorr");
 MODULE_LICENSE("GPL");

+ 16 - 2
drivers/media/dvb/frontends/dvb-pll.h

@@ -5,6 +5,9 @@
 #ifndef __DVB_PLL_H__
 #define __DVB_PLL_H__
 
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
 struct dvb_pll_desc {
 	char *name;
 	u32  min;
@@ -31,7 +34,7 @@ extern struct dvb_pll_desc dvb_pll_unknown_1;
 extern struct dvb_pll_desc dvb_pll_tua6010xs;
 extern struct dvb_pll_desc dvb_pll_env57h1xd5;
 extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_tdvs_tua6034;
+extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
 extern struct dvb_pll_desc dvb_pll_tda665x;
 extern struct dvb_pll_desc dvb_pll_fmd1216me;
 extern struct dvb_pll_desc dvb_pll_tded4;
@@ -44,7 +47,18 @@ extern struct dvb_pll_desc dvb_pll_philips_td1316;
 
 extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
 
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 		      u32 freq, int bandwidth);
 
+/**
+ * Attach a dvb-pll to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param desc dvb_pll_desc to use.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+
 #endif

+ 8 - 13
drivers/media/dvb/frontends/dvb_dummy_fe.c

@@ -30,7 +30,6 @@
 
 
 struct dvb_dummy_fe_state {
-	struct dvb_frontend_ops ops;
 	struct dvb_frontend frontend;
 };
 
@@ -77,6 +76,11 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten
 
 static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
+	if (fe->ops->tuner_ops->set_params) {
+		fe->ops->tuner_ops->set_params(fe, p);
+		if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
+	}
+
 	return 0;
 }
 
@@ -116,11 +120,8 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
 	state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
-	/* setup the state */
-	memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
-
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -139,11 +140,8 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
 	state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
-	/* setup the state */
-	memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
-
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -162,11 +160,8 @@ struct dvb_frontend* dvb_dummy_fe_qam_attach()
 	state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
-	/* setup the state */
-	memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
-
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 

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

@@ -0,0 +1,149 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#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"
+#include "isl6421.h"
+
+struct isl6421 {
+	u8			config;
+	u8			override_or;
+	u8			override_and;
+	struct i2c_adapter	*i2c;
+	u8			i2c_addr;
+	void			(*release_chain)(struct dvb_frontend* fe);
+};
+
+static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
+				.buf = &isl6421->config,
+				.len = sizeof(isl6421->config) };
+
+	isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1);
+
+	switch(voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		isl6421->config |= ISL6421_EN1;
+		break;
+	case SEC_VOLTAGE_18:
+		isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	isl6421->config |= isl6421->override_or;
+	isl6421->config &= isl6421->override_and;
+
+	return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
+				.buf = &isl6421->config,
+				.len = sizeof(isl6421->config) };
+
+	if (arg)
+		isl6421->config |= ISL6421_LLC1;
+	else
+		isl6421->config &= ~ISL6421_LLC1;
+
+	isl6421->config |= isl6421->override_or;
+	isl6421->config &= isl6421->override_and;
+
+	return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6421_release(struct dvb_frontend *fe)
+{
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+
+	/* power off */
+	isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data & call next release routine */
+	fe->ops.release = isl6421->release_chain;
+	kfree(fe->misc_priv);
+	fe->misc_priv = NULL;
+	if (fe->ops.release)
+		fe->ops.release(fe);
+}
+
+int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+		   u8 override_set, u8 override_clear)
+{
+	struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
+	if (!isl6421)
+		return -ENOMEM;
+
+	/* default configuration */
+	isl6421->config = ISL6421_ISEL1;
+	isl6421->i2c = i2c;
+	isl6421->i2c_addr = i2c_addr;
+	fe->misc_priv = isl6421;
+
+	/* bits which should be forced to '1' */
+	isl6421->override_or = override_set;
+
+	/* bits which should be forced to '0' */
+	isl6421->override_and = ~override_clear;
+
+	/* detect if it is present or not */
+	if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		kfree(isl6421);
+		fe->misc_priv = NULL;
+		return -EIO;
+	}
+
+	/* install release callback */
+	isl6421->release_chain = fe->ops.release;
+	fe->ops.release = isl6421_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = isl6421_set_voltage;
+	fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+
+	return 0;
+}
+EXPORT_SYMBOL(isl6421_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
+MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
+MODULE_LICENSE("GPL");

+ 46 - 0
drivers/media/dvb/frontends/isl6421.h

@@ -0,0 +1,46 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6421_H
+#define _ISL6421_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+#define ISL6421_OLF1	0x01
+#define ISL6421_EN1	0x02
+#define ISL6421_VSEL1	0x04
+#define ISL6421_LLC1	0x08
+#define ISL6421_ENT1	0x10
+#define ISL6421_ISEL1	0x20
+#define ISL6421_DCL	0x40
+
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+			  u8 override_set, u8 override_clear);
+
+#endif

+ 5 - 6
drivers/media/dvb/frontends/l64781.c

@@ -32,7 +32,6 @@
 
 struct l64781_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct l64781_config* config;
 	struct dvb_frontend frontend;
 
@@ -141,7 +140,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
 	u8 val0x06;
 	int bw = p->bandwidth - BANDWIDTH_8_MHZ;
 
-	state->config->pll_set(fe, param);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, param);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	if (param->inversion != INVERSION_ON &&
 	    param->inversion != INVERSION_OFF)
@@ -463,8 +465,6 @@ static int l64781_init(struct dvb_frontend* fe)
 	/* Everything is two's complement, soft bit and CSI_OUT too */
 	l64781_writereg (state, 0x1e, 0x09);
 
-	if (state->config->pll_init) state->config->pll_init(fe);
-
 	/* delay a bit after first init attempt */
 	if (state->first) {
 		state->first = 0;
@@ -508,7 +508,6 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
 	state->first = 1;
 
 	/**
@@ -554,7 +553,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 

+ 0 - 4
drivers/media/dvb/frontends/l64781.h

@@ -29,10 +29,6 @@ struct l64781_config
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 

+ 64 - 0
drivers/media/dvb/frontends/lg_h06xf.h

@@ -0,0 +1,64 @@
+/*
+ *  lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF
+ *
+ *  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 _LG_H06XF_H_
+#define _LG_H06XF_H_
+#include "dvb-pll.h"
+
+static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap,
+		     struct dvb_frontend_parameters* params)
+{
+	u8 buf[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+	int err;
+
+	dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+		printk(KERN_WARNING "lg_h06xf: %s error "
+			"(addr %02x <- %02x, err = %i)\n",
+			__FUNCTION__, buf[0], buf[1], err);
+		if (err < 0)
+			return err;
+		else
+			return -EREMOTEIO;
+	}
+
+	/* Set the Auxiliary Byte. */
+	buf[0] = buf[2];
+	buf[0] &= ~0x20;
+	buf[0] |= 0x18;
+	buf[1] = 0x50;
+	msg.len = 2;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+		printk(KERN_WARNING "lg_h06xf: %s error "
+			"(addr %02x <- %02x, err = %i)\n",
+			__FUNCTION__, buf[0], buf[1], err);
+		if (err < 0)
+			return err;
+		else
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+#endif

+ 11 - 8
drivers/media/dvb/frontends/lgdt330x.c

@@ -29,6 +29,7 @@
  *   DViCO FusionHDTV 5 Lite
  *   DViCO FusionHDTV 5 USB Gold
  *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
+ *   pcHDTV HD5500
  *
  * TODO:
  * signal strength always returns 0.
@@ -59,7 +60,6 @@ if (debug) printk(KERN_DEBUG "lgdt330x: " args); \
 struct lgdt330x_state
 {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 
 	/* Configuration settings */
 	const struct lgdt330x_config* config;
@@ -399,8 +399,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
 	}
 
 	/* Tune to the specified frequency */
-	if (state->config->pll_set)
-		state->config->pll_set(fe, param);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, param);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	/* Keep track of the new frequency */
 	/* FIXME this is the wrong way to do this...           */
@@ -672,6 +674,7 @@ static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr)
 
 	if (state->current_modulation == VSB_8) {
 
+		i2c_read_demod_bytes(state, 0x6e, buf, 5);
 		/* Phase Tracker Mean-Square Error Register for VSB */
 		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
 	} else {
@@ -721,16 +724,19 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
 	/* Setup the state */
 	state->config = config;
 	state->i2c = i2c;
+
+	/* Create dvb_frontend */
 	switch (config->demod_chip) {
 	case LGDT3302:
-		memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	case LGDT3303:
-		memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	default:
 		goto error;
 	}
+	state->frontend.demodulator_priv = state;
 
 	/* Verify communication with demod chip */
 	if (i2c_read_demod_bytes(state, 2, buf, 1))
@@ -739,9 +745,6 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
 	state->current_frequency = -1;
 	state->current_modulation = -1;
 
-	/* Create dvb_frontend */
-	state->frontend.ops = &state->ops;
-	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
 error:

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

@@ -43,7 +43,6 @@ struct lgdt330x_config
 
 	/* PLL interface */
 	int (*pll_rf_set) (struct dvb_frontend* fe, int index);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 
 	/* Need to set device param for start_dma */
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);

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

@@ -0,0 +1,145 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#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"
+#include "lnbp21.h"
+
+struct lnbp21 {
+	u8			config;
+	u8			override_or;
+	u8			override_and;
+	struct i2c_adapter	*i2c;
+	void			(*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+	switch(voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		lnbp21->config |= LNBP21_EN;
+		break;
+	case SEC_VOLTAGE_18:
+		lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	if (arg)
+		lnbp21->config |= LNBP21_LLC;
+	else
+		lnbp21->config &= ~LNBP21_LLC;
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_release(struct dvb_frontend *fe)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+	/* LNBP power off */
+	lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data & call next release routine */
+	fe->ops.release = lnbp21->release_chain;
+	kfree(fe->misc_priv);
+	fe->misc_priv = NULL;
+	if (fe->ops.release)
+		fe->ops.release(fe);
+}
+
+int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+	struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+	if (!lnbp21)
+		return -ENOMEM;
+
+	/* default configuration */
+	lnbp21->config = LNBP21_ISEL;
+	lnbp21->i2c = i2c;
+	fe->misc_priv = lnbp21;
+
+	/* bits which should be forced to '1' */
+	lnbp21->override_or = override_set;
+
+	/* bits which should be forced to '0' */
+	lnbp21->override_and = ~override_clear;
+
+	/* detect if it is present or not */
+	if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		kfree(lnbp21);
+		fe->misc_priv = NULL;
+		return -EIO;
+	}
+
+	/* install release callback */
+	lnbp21->release_chain = fe->ops.release;
+	fe->ops.release = lnbp21_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = lnbp21_set_voltage;
+	fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+	return 0;
+}
+EXPORT_SYMBOL(lnbp21_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21");
+MODULE_AUTHOR("Oliver Endriss");
+MODULE_LICENSE("GPL");

+ 4 - 98
drivers/media/dvb/frontends/lnbp21.h

@@ -27,7 +27,7 @@
 #ifndef _LNBP21_H
 #define _LNBP21_H
 
-/* system register */
+/* system register bits */
 #define LNBP21_OLF	0x01
 #define LNBP21_OTF	0x02
 #define LNBP21_EN	0x04
@@ -37,103 +37,9 @@
 #define LNBP21_ISEL	0x40
 #define LNBP21_PCL	0x80
 
-struct lnbp21 {
-	u8			config;
-	u8			override_or;
-	u8			override_and;
-	struct i2c_adapter	*i2c;
-	void			(*release_chain)(struct dvb_frontend* fe);
-};
+#include <linux/dvb/frontend.h>
 
-static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
-				.buf = &lnbp21->config,
-				.len = sizeof(lnbp21->config) };
-
-	lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
-
-	switch(voltage) {
-	case SEC_VOLTAGE_OFF:
-		break;
-	case SEC_VOLTAGE_13:
-		lnbp21->config |= LNBP21_EN;
-		break;
-	case SEC_VOLTAGE_18:
-		lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	lnbp21->config |= lnbp21->override_or;
-	lnbp21->config &= lnbp21->override_and;
-
-	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
-				.buf = &lnbp21->config,
-				.len = sizeof(lnbp21->config) };
-
-	if (arg)
-		lnbp21->config |= LNBP21_LLC;
-	else
-		lnbp21->config &= ~LNBP21_LLC;
-
-	lnbp21->config |= lnbp21->override_or;
-	lnbp21->config &= lnbp21->override_and;
-
-	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void lnbp21_exit(struct dvb_frontend *fe)
-{
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-
-	/* LNBP power off */
-	lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-	/* free data & call next release routine */
-	fe->ops->release = lnbp21->release_chain;
-	kfree(fe->misc_priv);
-	fe->misc_priv = NULL;
-	if (fe->ops->release)
-		fe->ops->release(fe);
-}
-
-static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
-{
-	struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
-
-	if (!lnbp21)
-		return -ENOMEM;
-
-	/* default configuration */
-	lnbp21->config = LNBP21_ISEL;
-
-	/* bits which should be forced to '1' */
-	lnbp21->override_or = override_set;
-
-	/* bits which should be forced to '0' */
-	lnbp21->override_and = ~override_clear;
-
-	/* install release callback */
-	lnbp21->release_chain = fe->ops->release;
-	fe->ops->release = lnbp21_exit;
-
-	/* override frontend ops */
-	fe->ops->set_voltage = lnbp21_set_voltage;
-	fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-
-	lnbp21->i2c = i2c;
-	fe->misc_priv = lnbp21;
-
-	return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-}
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
 
 #endif

+ 26 - 20
drivers/media/dvb/frontends/mt312.c

@@ -39,7 +39,6 @@
 
 struct mt312_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	/* configuration settings */
 	const struct mt312_config* config;
 	struct dvb_frontend frontend;
@@ -277,12 +276,6 @@ static int mt312_initfe(struct dvb_frontend* fe)
 	if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
 		return ret;
 
-	if (state->config->pll_init) {
-		mt312_writereg(state, GPP_CTRL, 0x40);
-		state->config->pll_init(fe);
-		mt312_writereg(state, GPP_CTRL, 0x00);
-	}
-
 	return 0;
 }
 
@@ -477,16 +470,16 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 
 	dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
 
-	if ((p->frequency < fe->ops->info.frequency_min)
-	    || (p->frequency > fe->ops->info.frequency_max))
+	if ((p->frequency < fe->ops.info.frequency_min)
+	    || (p->frequency > fe->ops.info.frequency_max))
 		return -EINVAL;
 
 	if ((p->inversion < INVERSION_OFF)
 	    || (p->inversion > INVERSION_ON))
 		return -EINVAL;
 
-	if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min)
-	    || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max))
+	if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min)
+	    || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
 		return -EINVAL;
 
 	if ((p->u.qpsk.fec_inner < FEC_NONE)
@@ -529,9 +522,10 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 		return -EINVAL;
 	}
 
-	mt312_writereg(state, GPP_CTRL, 0x40);
-	state->config->pll_set(fe, p);
-	mt312_writereg(state, GPP_CTRL, 0x00);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	/* sr = (u16)(sr * 256.0 / 1000000.0) */
 	sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
@@ -578,6 +572,17 @@ static int mt312_get_frontend(struct dvb_frontend* fe,
 	return 0;
 }
 
+static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct mt312_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return mt312_writereg(state, GPP_CTRL, 0x40);
+	} else {
+		return mt312_writereg(state, GPP_CTRL, 0x00);
+	}
+}
+
 static int mt312_sleep(struct dvb_frontend* fe)
 {
 	struct mt312_state *state = fe->demodulator_priv;
@@ -633,6 +638,7 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
 
 	.init = mt312_initfe,
 	.sleep = mt312_sleep,
+	.i2c_gate_ctrl = mt312_i2c_gate_ctrl,
 
 	.set_frontend = mt312_set_frontend,
 	.get_frontend = mt312_get_frontend,
@@ -663,19 +669,22 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check if the demod is there */
 	if (mt312_readreg(state, ID, &state->id) < 0)
 		goto error;
 
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
 	switch (state->id) {
 	case ID_VP310:
-		strcpy(state->ops.info.name, "Zarlink VP310 DVB-S");
+		strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
 		state->frequency = 90;
 		break;
 	case ID_MT312:
-		strcpy(state->ops.info.name, "Zarlink MT312 DVB-S");
+		strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
 		state->frequency = 60;
 		break;
 	default:
@@ -683,9 +692,6 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
 		goto error;
 	}
 
-	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
-	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
 error:

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません