Merge master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb
Linus Torvalds [Mon, 9 Jan 2006 21:03:58 +0000 (13:03 -0800)]
203 files changed:
Documentation/dvb/avermedia.txt
Documentation/dvb/get_dvb_firmware
Documentation/dvb/ttusb-dec.txt
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_hlp.c
drivers/media/common/saa7146_vbi.c
drivers/media/common/saa7146_video.c
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/b2c2/flexcop-reg.h
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dst_ca.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/cinergyT2/Kconfig
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-core/Kconfig
drivers/media/dvb/dvb-core/Makefile
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_filter.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvb_ringbuffer.c
drivers/media/dvb/dvb-core/dvb_ringbuffer.h
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/cxusb.h
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dtt200u.c
drivers/media/dvb/dvb-usb/dtt200u.h
drivers/media/dvb/dvb-usb/dvb-usb-common.h
drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-init.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/nova-t-usb2.c
drivers/media/dvb/dvb-usb/vp702x-fe.c
drivers/media/dvb/dvb-usb/vp702x.h
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/bcm3510.c
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx24110.c
drivers/media/dvb/frontends/cx24123.c [new file with mode: 0644]
drivers/media/dvb/frontends/cx24123.h [new file with mode: 0644]
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/lgdt330x.c
drivers/media/dvb/frontends/nxt2002.c
drivers/media/dvb/frontends/nxt6000.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/s5h1420.c
drivers/media/dvb/frontends/sp8870.c
drivers/media/dvb/frontends/sp887x.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/stv0299.h
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/pluto2/Kconfig
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/Makefile
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_hw.c
drivers/media/dvb/ttpci/av7110_hw.h
drivers/media/dvb/ttpci/av7110_ir.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-core.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttpci/ttpci-eeprom.c
drivers/media/dvb/ttusb-budget/Kconfig
drivers/media/dvb/ttusb-dec/Kconfig
drivers/media/dvb/ttusb-dec/ttusb_dec.c
drivers/media/dvb/ttusb-dec/ttusbdecfe.c
drivers/media/radio/miropcm20-radio.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maestro.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/bt832.c
drivers/media/video/bttv-cards.c
drivers/media/video/bttv-driver.c
drivers/media/video/bttv-gpio.c
drivers/media/video/bttv-i2c.c
drivers/media/video/bttv-input.c [moved from drivers/media/video/ir-kbd-gpio.c with 73% similarity]
drivers/media/video/bttv-vbi.c
drivers/media/video/bttv.h
drivers/media/video/bttvp.h
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/compat_ioctl32.c [new file with mode: 0644]
drivers/media/video/cpia.c
drivers/media/video/cs53l32a.c
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-firmware.c
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx25840/cx25840.h
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/Makefile
drivers/media/video/cx88/cx88-alsa.c [new file with mode: 0644]
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88-vp3054-i2c.c [new file with mode: 0644]
drivers/media/video/cx88/cx88-vp3054-i2c.h [new file with mode: 0644]
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/meye.c
drivers/media/video/msp3400-driver.c [new file with mode: 0644]
drivers/media/video/msp3400-kthreads.c [new file with mode: 0644]
drivers/media/video/msp3400.c [deleted file]
drivers/media/video/msp3400.h
drivers/media/video/mt20xx.c
drivers/media/video/mxb.c
drivers/media/video/pms.c
drivers/media/video/saa5249.c
drivers/media/video/saa6588.c
drivers/media/video/saa7115.c
drivers/media/video/saa711x.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-oss.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/stradis.c
drivers/media/video/tda7432.c
drivers/media/video/tda8290.c
drivers/media/video/tda9875.c
drivers/media/video/tda9887.c
drivers/media/video/tea5767.c
drivers/media/video/tuner-core.c
drivers/media/video/tuner-simple.c
drivers/media/video/tvaudio.c
drivers/media/video/tveeprom.c
drivers/media/video/tvmixer.c
drivers/media/video/tvp5150.c
drivers/media/video/v4l1-compat.c
drivers/media/video/v4l2-common.c
drivers/media/video/videodev.c
drivers/media/video/w9966.c
drivers/media/video/wm8775.c
drivers/media/video/zoran_driver.c
drivers/media/video/zr36120.c
drivers/usb/media/dsbr100.c
drivers/usb/media/ov511.c
drivers/usb/media/pwc/pwc-if.c
drivers/usb/media/se401.c
drivers/usb/media/stv680.c
drivers/usb/media/usbvideo.c
drivers/usb/media/vicam.c
drivers/usb/media/w9968cf.c
fs/compat_ioctl.c
include/linux/compat_ioctl.h
include/linux/dvb/frontend.h
include/linux/i2c-id.h
include/linux/video_decoder.h
include/linux/videodev2.h
include/media/audiochip.h
include/media/saa7146_vv.h
include/media/tuner.h
include/media/v4l2-common.h

index 2dc260b..068070f 100644 (file)
@@ -150,7 +150,8 @@ Getting the card going
 
    The frontend module sp887x.o, requires an external   firmware.
    Please use  the  command "get_dvb_firmware sp887x" to download
-   it. Then copy it to /usr/lib/hotplug/firmware.
+   it. Then copy it to /usr/lib/hotplug/firmware or /lib/firmware/
+   (depending on configuration of firmware hotplug).
 
 Receiving DVB-T in Australia
 
index be6eb4c..75c28a1 100644 (file)
@@ -23,7 +23,7 @@ use IO::Handle;
 
 @components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
                "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
-               "or51211", "or51132_qam", "or51132_vsb");
+               "or51211", "or51132_qam", "or51132_vsb", "bluebird");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -34,7 +34,11 @@ for ($i=0; $i < scalar(@components); $i++) {
     if ($cid eq $components[$i]) {
        $outfile = eval($cid);
        die $@ if $@;
-       print STDERR "Firmware $outfile extracted successfully. Now copy it to either /lib/firmware or /usr/lib/hotplug/firmware/ (depending on your hotplug version).\n";
+       print STDERR <<EOF;
+Firmware $outfile extracted successfully.
+Now copy it to either /usr/lib/hotplug/firmware or /lib/firmware
+(depending on configuration of firmware hotplug).
+EOF
        exit(0);
     }
 }
@@ -243,7 +247,7 @@ sub nxt2002 {
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
 
     checkstandard();
-    
+
     wgetfile($sourcefile, $url);
     unzip($sourcefile, $tmpdir);
     verify("$tmpdir/SkyNETU.sys", $hash);
@@ -308,6 +312,19 @@ sub or51132_vsb {
     $fwfile;
 }
 
+sub bluebird {
+       my $url = "http://www.linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
+       my $outfile = "dvb-usb-bluebird-01.fw";
+       my $hash = "658397cb9eba9101af9031302671f49d";
+
+       checkstandard();
+
+       wgetfile($outfile, $url);
+       verify($outfile,$hash);
+
+       $outfile;
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
index 5c1e984..b2f271c 100644 (file)
@@ -41,4 +41,5 @@ Hotplug Firmware Loading for 2.6 kernels
 For 2.6 kernels the firmware is loaded at the point that the driver module is
 loaded.  See linux/Documentation/dvb/firmware.txt for more information.
 
-Copy the three files downloaded above into the /usr/lib/hotplug/firmware directory.
+Copy the three files downloaded above into the /usr/lib/hotplug/firmware or
+/lib/firmware directory (depending on configuration of firmware hotplug).
index 330246a..74fb085 100644 (file)
 140 -> Osprey 440                                          [0070:ff07]
 141 -> Asound Skyeye PCTV
 142 -> Sabrent TV-FM (bttv version)
+143 -> Hauppauge ImpactVCB (bt878)                         [0070:13eb]
index a1017d1..34b6e59 100644 (file)
@@ -16,7 +16,7 @@
  15 -> DViCO FusionHDTV DVB-T1                             [18ac:db00]
  16 -> KWorld LTV883RF
  17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810]
- 18 -> Hauppauge Nova-T DVB-T                              [0070:9002]
+ 18 -> Hauppauge Nova-T DVB-T                              [0070:9002,0070:9001]
  19 -> Conexant DVB-T reference design                     [14f1:0187]
  20 -> Provideo PV259                                      [1540:2580]
  21 -> DViCO FusionHDTV DVB-T Plus                         [18ac:db10]
  34 -> ATI HDTV Wonder                                     [1002:a101]
  35 -> WinFast DTV1000-T                                   [107d:665f]
  36 -> AVerTV 303 (M126)                                   [1461:000a]
+ 37 -> Hauppauge Nova-S-Plus DVB-S                         [0070:9201,0070:9202]
+ 38 -> Hauppauge Nova-SE2 DVB-S                            [0070:9200]
+ 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]
+ 43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1]
+ 44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50]
index efb708e..cb3a59b 100644 (file)
@@ -56,7 +56,7 @@
  55 -> LifeView FlyDVB-T DUO                    [5168:0502,5168:0306]
  56 -> Avermedia AVerTV 307                     [1461:a70a]
  57 -> Avermedia AVerTV GO 007 FM               [1461:f31f]
- 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0370,1421:1370]
+ 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0351,1421:0370,1421:1370]
  59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
  60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502]
  61 -> Philips TOUGH DVB-T reference design     [1131:2004]
@@ -81,4 +81,5 @@
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
  82 -> MSI TV@Anywhere plus                     [1462:6231]
-
+ 83 -> Terratec Cinergy 250 PCI TV              [153b:1160]
+ 84 -> LifeView FlyDVB Trio                     [5168:0319]
index 9d6544e..0bf3d5b 100644 (file)
@@ -40,7 +40,7 @@ tuner=38 - Philips PAL/SECAM multi (FM1216ME MK3)
 tuner=39 - LG NTSC (newer TAPC series)
 tuner=40 - HITACHI V7-J180AT
 tuner=41 - Philips PAL_MK (FI1216 MK)
-tuner=42 - Philips 1236D ATSC/NTSC daul in
+tuner=42 - Philips 1236D ATSC/NTSC dual in
 tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
 tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
 tuner=45 - Microtune 4049 FM5
@@ -50,7 +50,7 @@ tuner=48 - Tenna TNF 8831 BGFF)
 tuner=49 - Microtune 4042 FI5 ATSC/NTSC dual in
 tuner=50 - TCL 2002N
 tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
-tuner=52 - Thomson DDT 7610 (ATSC/NTSC)
+tuner=52 - Thomson DTT 7610 (ATSC/NTSC)
 tuner=53 - Philips FQ1286
 tuner=54 - tda8290+75
 tuner=55 - TCL 2002MB
@@ -58,7 +58,7 @@ tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
 tuner=57 - Philips FQ1236A MK4
 tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF
 tuner=59 - Ymec TVision TVF-5533MF
-tuner=60 - Thomson DDT 7611 (ATSC/NTSC)
+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
index 09ec964..b614612 100644 (file)
@@ -253,7 +253,10 @@ static int fops_open(struct inode *inode, struct file *file)
 
        if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                DEB_S(("initializing vbi...\n"));
-               result = saa7146_vbi_uops.open(dev,file);
+               if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+                       result = saa7146_vbi_uops.open(dev,file);
+               if (dev->ext_vv_data->vbi_fops.open)
+                       dev->ext_vv_data->vbi_fops.open(inode, file);
        } else {
                DEB_S(("initializing video...\n"));
                result = saa7146_video_uops.open(dev,file);
@@ -289,7 +292,10 @@ static int fops_release(struct inode *inode, struct file *file)
                return -ERESTARTSYS;
 
        if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-               saa7146_vbi_uops.release(dev,file);
+               if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+                       saa7146_vbi_uops.release(dev,file);
+               if (dev->ext_vv_data->vbi_fops.release)
+                       dev->ext_vv_data->vbi_fops.release(inode, file);
        } else {
                saa7146_video_uops.release(dev,file);
        }
@@ -332,6 +338,7 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
                BUG();
                return 0;
        }
+
        return videobuf_mmap_mapper(q,vma);
 }
 
@@ -381,7 +388,10 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
                }
        case V4L2_BUF_TYPE_VBI_CAPTURE: {
 //             DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", file, data, (unsigned long)count));
-               return saa7146_vbi_uops.read(file,data,count,ppos);
+               if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+                       return saa7146_vbi_uops.read(file,data,count,ppos);
+               else
+                       return -EINVAL;
                }
                break;
        default:
@@ -390,12 +400,31 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
        }
 }
 
+static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+       struct saa7146_fh *fh = file->private_data;
+
+       switch (fh->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return -EINVAL;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               if (fh->dev->ext_vv_data->vbi_fops.write)
+                       return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
+               else
+                       return -EINVAL;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+}
+
 static struct file_operations video_fops =
 {
        .owner          = THIS_MODULE,
        .open           = fops_open,
        .release        = fops_release,
        .read           = fops_read,
+       .write          = fops_write,
        .poll           = fops_poll,
        .mmap           = fops_mmap,
        .ioctl          = fops_ioctl,
@@ -467,7 +496,8 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
        memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
 
        saa7146_video_uops.init(dev,vv);
-       saa7146_vbi_uops.init(dev,vv);
+       if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
+               saa7146_vbi_uops.init(dev,vv);
 
        dev->vv_data = vv;
        dev->vv_callback = &vv_callback;
index ec52dff..33bec8a 100644 (file)
@@ -562,19 +562,26 @@ static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int
 
        int b_depth = vv->ov_fmt->depth;
        int b_bpl = vv->ov_fb.fmt.bytesperline;
-       u32 base = (u32)vv->ov_fb.base;
+       /* The unsigned long cast is to remove a 64-bit compile warning since
+          it looks like a 64-bit address is cast to a 32-bit value, even
+          though the base pointer is really a 32-bit physical address that
+          goes into a 32-bit DMA register.
+          FIXME: might not work on some 64-bit platforms, but see the FIXME
+          in struct v4l2_framebuffer (videodev2.h) for that.
+        */
+       u32 base = (u32)(unsigned long)vv->ov_fb.base;
 
        struct  saa7146_video_dma vdma1;
 
        /* calculate memory offsets for picture, look if we shall top-down-flip */
        vdma1.pitch     = 2*b_bpl;
        if ( 0 == vv->vflip ) {
-               vdma1.base_even = (u32)base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+               vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
                vdma1.base_odd  = vdma1.base_even + (vdma1.pitch / 2);
                vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
        }
        else {
-               vdma1.base_even = (u32)base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
+               vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
                vdma1.base_odd  = vdma1.base_even - (vdma1.pitch / 2);
                vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
        }
index 063986e..468d3c9 100644 (file)
@@ -500,9 +500,9 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
 }
 
 struct saa7146_use_ops saa7146_vbi_uops = {
-       .init           = vbi_init,
-       .open           = vbi_open,
+       .init           = vbi_init,
+       .open           = vbi_open,
        .release        = vbi_close,
        .irq_done       = vbi_irq_done,
-       .read           = vbi_read,
+       .read           = vbi_read,
 };
index 1d96102..7ebac79 100644 (file)
@@ -151,8 +151,8 @@ static int try_win(struct saa7146_dev *dev, struct v4l2_window *win)
 
        if (V4L2_FIELD_ANY == field) {
                field = (win->w.height > maxh/2)
-                       ? V4L2_FIELD_INTERLACED
-                       : V4L2_FIELD_TOP;
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_TOP;
                }
        switch (field) {
        case V4L2_FIELD_TOP:
@@ -1114,10 +1114,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                return 0;
        }
        case VIDIOC_OVERLAY:
-
-
-
-
        {
                int on = *(int *)arg;
                int err = 0;
@@ -1359,7 +1355,6 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
        saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
 }
 
-
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
        struct file *file = q->priv_data;
index 21a9045..0b940e1 100644 (file)
@@ -298,7 +298,7 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
 }
 
 static int lgdt3303_pll_set(struct dvb_frontend* fe,
-                           struct dvb_frontend_parameters* params)
+                           struct dvb_frontend_parameters* params)
 {
        struct flexcop_device *fc = fe->dvb->priv;
        u8 buf[4];
@@ -485,12 +485,16 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
 /* try to figure out the frontend, each card/box can have on of the following list */
 int flexcop_frontend_init(struct flexcop_device *fc)
 {
+       struct dvb_frontend_ops *ops;
+
        /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
        if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
-               fc->fe->ops->set_voltage = flexcop_set_voltage;
+               ops = fc->fe->ops;
+
+               ops->set_voltage = flexcop_set_voltage;
 
-               fc->fe_sleep             = fc->fe->ops->sleep;
-               fc->fe->ops->sleep       = flexcop_sleep;
+               fc->fe_sleep             = ops->sleep;
+               ops->sleep               = flexcop_sleep;
 
                fc->dev_type          = FC_SKY;
                info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
@@ -522,15 +526,17 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        } else
        /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
        if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
-               fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
-               fc->fe->ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
-               fc->fe->ops->set_tone               = flexcop_set_tone;
-               fc->fe->ops->set_voltage            = flexcop_set_voltage;
+               ops = fc->fe->ops;
+
+               ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+               ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
+               ops->set_tone               = flexcop_set_tone;
+               ops->set_voltage            = flexcop_set_voltage;
 
-               fc->fe_sleep                        = fc->fe->ops->sleep;
-               fc->fe->ops->sleep                  = flexcop_sleep;
+               fc->fe_sleep                = ops->sleep;
+               ops->sleep                  = flexcop_sleep;
 
-               fc->dev_type                        = FC_SKY_OLD;
+               fc->dev_type                = FC_SKY_OLD;
                info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
        }
 
@@ -540,8 +546,9 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        } else {
                if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
                        err("frontend registration failed!");
-                       if (fc->fe->ops->release != NULL)
-                               fc->fe->ops->release(fc->fe);
+                       ops = fc->fe->ops;
+                       if (ops->release != NULL)
+                               ops->release(fc->fe);
                        fc->fe = NULL;
                        return -EINVAL;
                }
index 23cc643..3153f95 100644 (file)
@@ -39,11 +39,13 @@ extern const char *flexcop_device_names[];
 /* FlexCop IBI Registers */
 #if defined(__LITTLE_ENDIAN)
        #include "flexcop_ibi_value_le.h"
-#elif defined(__BIG_ENDIAN)
+#else
+#if defined(__BIG_ENDIAN)
        #include "flexcop_ibi_value_be.h"
 #else
        #error no endian defined
 #endif
+#endif
 
 #define fc_data_Tag_ID_DVB  0x3e
 #define fc_data_Tag_ID_ATSC 0x3f
index 8977c7a..3a2ff1c 100644 (file)
@@ -1341,30 +1341,40 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
        return 0;
 }
 
-static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dst_set_frontend(struct dvb_frontend* fe,
+                           struct dvb_frontend_parameters* p,
+                           unsigned int mode_flags,
+                           int *delay,
+                           fe_status_t *status)
 {
        struct dst_state *state = fe->demodulator_priv;
 
-       dst_set_freq(state, p->frequency);
-       dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+       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);
+               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);
        }
-       dst_write_tuna(fe);
 
+       if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+               dst_read_status(fe, status);
+
+       *delay = HZ/10;
        return 0;
 }
 
@@ -1445,7 +1455,7 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
 
        .release = dst_release,
        .init = dst_init,
-       .set_frontend = dst_set_frontend,
+       .tune = dst_set_frontend,
        .get_frontend = dst_get_frontend,
        .read_status = dst_read_status,
        .read_signal_strength = dst_read_signal_strength,
@@ -1469,7 +1479,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
 
        .release = dst_release,
        .init = dst_init,
-       .set_frontend = dst_set_frontend,
+       .tune = dst_set_frontend,
        .get_frontend = dst_get_frontend,
        .read_status = dst_read_status,
        .read_signal_strength = dst_read_signal_strength,
@@ -1496,7 +1506,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
 
        .release = dst_release,
        .init = dst_init,
-       .set_frontend = dst_set_frontend,
+       .tune = dst_set_frontend,
        .get_frontend = dst_get_frontend,
        .read_status = dst_read_status,
        .read_signal_strength = dst_read_signal_strength,
index 2239651..c650b4b 100644 (file)
@@ -283,16 +283,17 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message,
                hw_buffer->msg[4] = 0x03;
                hw_buffer->msg[5] = length & 0xff;
                hw_buffer->msg[6] = 0x00;
+
                /*
                 *      Need to compute length for EN50221 section 8.3.2, for the time being
                 *      assuming 8.3.2 is not applicable
                 */
                memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
        }
+
        return 0;
 }
 
-
 static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
 {
        if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
index 77977e9..01b4e0a 100644 (file)
@@ -600,7 +600,6 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
        struct dst_state* state = NULL;
 
        switch(type) {
-#ifdef BTTV_BOARD_DVICO_DVBT_LITE
        case BTTV_BOARD_DVICO_DVBT_LITE:
                card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
                if (card->fe != NULL) {
@@ -608,22 +607,15 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                        card->fe->ops->info.frequency_max = 862000000;
                }
                break;
-#endif
 
-#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
        case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
                lgdt330x_reset(card);
                card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
                if (card->fe != NULL)
                        dprintk ("dvb_bt8xx: lgdt330x detected\n");
                break;
-#endif
 
-#ifdef BTTV_BOARD_TWINHAN_VP3021
-       case BTTV_BOARD_TWINHAN_VP3021:
-#else
        case BTTV_BOARD_NEBULA_DIGITV:
-#endif
                /*
                 * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
                 * this would be a cleaner solution than trying each frontend in turn.
@@ -812,9 +804,7 @@ static int dvb_bt8xx_probe(struct device *dev)
                card->irq_err_ignore = 0;
                break;
 
-#ifdef BTTV_BOARD_DVICO_DVBT_LITE
        case BTTV_BOARD_DVICO_DVBT_LITE:
-#endif
                card->gpio_mode = 0x0400C060;
                card->op_sync_orin = 0;
                card->irq_err_ignore = 0;
@@ -823,19 +813,13 @@ static int dvb_bt8xx_probe(struct device *dev)
                 * DA_APP(parallel) */
                break;
 
-#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
        case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
-#endif
                card->gpio_mode = 0x0400c060;
                card->op_sync_orin = BT878_RISC_SYNC_MASK;
                card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
                break;
 
-#ifdef BTTV_BOARD_TWINHAN_VP3021
-       case BTTV_BOARD_TWINHAN_VP3021:
-#else
        case BTTV_BOARD_NEBULA_DIGITV:
-#endif
        case BTTV_BOARD_AVDVBT_761:
                card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
                card->op_sync_orin = 0;
index 7cf4c4a..6018fcd 100644 (file)
@@ -21,35 +21,35 @@ config DVB_CINERGYT2_TUNING
 config DVB_CINERGYT2_STREAM_URB_COUNT
        int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
        depends on DVB_CINERGYT2_TUNING
-        default "32"
+       default "32"
        help
          USB Request Blocks for Highspeed Stream transfers are scheduled in
          a queue for the Host Controller.
 
          Usually the default value is a safe choice.
 
-         You may increase this number if you are using this device in a 
-         Server Environment with many high-traffic USB Highspeed devices 
+         You may increase this number if you are using this device in a
+         Server Environment with many high-traffic USB Highspeed devices
          sharing the same USB bus.
 
 
 config DVB_CINERGYT2_STREAM_BUF_SIZE
        int "Size of URB Stream Buffers for Highspeed Transfers"
        depends on DVB_CINERGYT2_TUNING
-        default "512"
+       default "512"
        help
          Should be a multiple of native buffer size of 512 bytes.
          Default value is a safe choice.
 
-         You may increase this number if you are using this device in a 
-         Server Environment with many high-traffic USB Highspeed devices 
+         You may increase this number if you are using this device in a
+         Server Environment with many high-traffic USB Highspeed devices
          sharing the same USB bus.
 
 
 config DVB_CINERGYT2_QUERY_INTERVAL
        int "Status update interval [milliseconds]"
        depends on DVB_CINERGYT2_TUNING
-        default "250"
+       default "250"
        help
          This is the interval for status readouts from the demodulator.
          You may try lower values if you need more responsive signal quality
@@ -64,9 +64,9 @@ 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 "yes"
        help
-         Enable this option if you want to use the onboard Infrared Remote 
+         Enable this option if you want to use the onboard Infrared Remote
          Control Receiver as Linux-Input device.
 
          Right now only the keycode table for the default Remote Control
@@ -77,7 +77,7 @@ config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
 config DVB_CINERGYT2_RC_QUERY_INTERVAL
        int "Infrared Remote Controller update interval [milliseconds]"
        depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-        default "50"
+       default "50"
        help
          If you have a very fast-repeating remote control you can try lower
          values, for normal consumer receivers the default value should be
index 1d69bf0..c4b4c5b 100644 (file)
@@ -131,6 +131,8 @@ struct cinergyt2 {
 
        wait_queue_head_t poll_wq;
        int pending_fe_events;
+       int disconnect_pending;
+       atomic_t inuse;
 
        void *streambuf;
        dma_addr_t streambuf_dmahandle;
@@ -343,7 +345,7 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct dvb_demux *demux = dvbdmxfeed->demux;
        struct cinergyt2 *cinergyt2 = demux->priv;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (cinergyt2->streaming == 0)
@@ -359,7 +361,7 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct dvb_demux *demux = dvbdmxfeed->demux;
        struct cinergyt2 *cinergyt2 = demux->priv;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (--cinergyt2->streaming == 0)
@@ -479,23 +481,37 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       int err;
+       int err = -ERESTARTSYS;
 
-       if ((err = dvb_generic_open(inode, file)))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+
+       if ((err = dvb_generic_open(inode, file))) {
+               up(&cinergyt2->sem);
                return err;
+       }
 
-       if (down_interruptible(&cinergyt2->sem))
-               return -ERESTARTSYS;
 
        if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
                cinergyt2_sleep(cinergyt2, 0);
                schedule_delayed_work(&cinergyt2->query_work, HZ/2);
        }
 
+       atomic_inc(&cinergyt2->inuse);
+
        up(&cinergyt2->sem);
        return 0;
 }
 
+static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
+{
+       dvb_unregister_device(cinergyt2->fedev);
+       dvb_unregister_adapter(&cinergyt2->adapter);
+
+       cinergyt2_free_stream_urbs(cinergyt2);
+       kfree(cinergyt2);
+}
+
 static int cinergyt2_release (struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
@@ -504,7 +520,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
        if (down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
-       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+       if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
                cancel_delayed_work(&cinergyt2->query_work);
                flush_scheduled_work();
                cinergyt2_sleep(cinergyt2, 1);
@@ -512,6 +528,11 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
 
        up(&cinergyt2->sem);
 
+       if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
+               warn("delayed unregister in release");
+               cinergyt2_unregister(cinergyt2);
+       }
+
        return dvb_generic_release(inode, file);
 }
 
@@ -519,7 +540,14 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
 {
        struct dvb_device *dvbdev = file->private_data;
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
+
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+
        poll_wait(file, &cinergyt2->poll_wq, wait);
+
+       up(&cinergyt2->sem);
+
        return (POLLIN | POLLRDNORM | POLLPRI);
 }
 
@@ -564,10 +592,15 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
                                (__u16 __user *) arg);
 
        case FE_READ_UNCORRECTED_BLOCKS:
-               /* UNC are already converted to host byte order... */
-               return put_user(stat->uncorrected_block_count,
-                               (__u32 __user *) arg);
+       {
+               uint32_t unc_count;
+
+               unc_count = stat->uncorrected_block_count;
+               stat->uncorrected_block_count = 0;
 
+               /* UNC are already converted to host byte order... */
+               return put_user(unc_count,(__u32 __user *) arg);
+       }
        case FE_SET_FRONTEND:
        {
                struct dvbt_set_parameters_msg *param = &cinergyt2->param;
@@ -580,7 +613,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
                if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
                        return -EFAULT;
 
-               if (down_interruptible(&cinergyt2->sem))
+               if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                        return -ERESTARTSYS;
 
                param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -691,7 +724,7 @@ static void cinergyt2_query_rc (void *data)
        struct cinergyt2_rc_event rc_events[12];
        int n, len, i;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return;
 
        len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
@@ -786,7 +819,6 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
 static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2)
 {
        cancel_delayed_work(&cinergyt2->rc_query_work);
-       flush_scheduled_work();
        input_unregister_device(cinergyt2->rc_input_dev);
 }
 
@@ -817,7 +849,7 @@ static void cinergyt2_query (void *data)
        uint8_t lock_bits;
        uint32_t unc;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return;
 
        unc = s->uncorrected_block_count;
@@ -917,28 +949,25 @@ static void cinergyt2_disconnect (struct usb_interface *intf)
 {
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-       if (down_interruptible(&cinergyt2->sem))
-               return;
+       flush_scheduled_work();
 
        cinergyt2_unregister_rc(cinergyt2);
 
+       cancel_delayed_work(&cinergyt2->query_work);
+       wake_up_interruptible(&cinergyt2->poll_wq);
+
        cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
-       dvb_net_release(&cinergyt2->dvbnet);
-       dvb_dmxdev_release(&cinergyt2->dmxdev);
-       dvb_dmx_release(&cinergyt2->demux);
-       dvb_unregister_device(cinergyt2->fedev);
-       dvb_unregister_adapter(&cinergyt2->adapter);
+       cinergyt2->disconnect_pending = 1;
 
-       cinergyt2_free_stream_urbs(cinergyt2);
-       up(&cinergyt2->sem);
-       kfree(cinergyt2);
+       if (!atomic_read(&cinergyt2->inuse))
+               cinergyt2_unregister(cinergyt2);
 }
 
 static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
 {
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (state.event > PM_EVENT_ON) {
@@ -961,7 +990,7 @@ static int cinergyt2_resume (struct usb_interface *intf)
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
        struct dvbt_set_parameters_msg *param = &cinergyt2->param;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (!cinergyt2->sleeping) {
@@ -1014,4 +1043,3 @@ module_exit (cinergyt2_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
-
index a9a7b34..12ee912 100644 (file)
@@ -5,7 +5,7 @@ config DVB_CORE
        help
          DVB core utility functions for device handling, software fallbacks etc.
          Say Y when you have a DVB card and want to use it. Say Y if your want
-         to build your drivers outside the kernel, but need the DVB core. All 
+         to build your drivers outside the kernel, but need the DVB core. All
          in-kernel drivers will select this automatically if needed.
          If unsure say N.
 
index c6baac2..7adb50c 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
-               dvb_ca_en50221.o dvb_frontend.o \
+               dvb_ca_en50221.o dvb_frontend.o \
                dvb_net.o dvb_ringbuffer.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
index 5956c35..4bb779a 100644 (file)
@@ -1745,9 +1745,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
 
        for (i = 0; i < ca->slot_count; i++) {
                dvb_ca_en50221_slot_shutdown(ca, i);
-               if (ca->slot_info[i].rx_buffer.data != NULL) {
-                       vfree(ca->slot_info[i].rx_buffer.data);
-               }
+               vfree(ca->slot_info[i].rx_buffer.data);
        }
        kfree(ca->slot_info);
        dvb_unregister_device(ca->dvbdev);
index c49fd0b..772003f 100644 (file)
@@ -409,16 +409,16 @@ static u8 *skip_pes_header(u8 **bufp)
 
        if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
                if (buf[7] & PTS_ONLY)
-                       pts = buf+9;
+                       pts = buf+9;
                else pts = NULL;
                buf = inbuf + 9 + inbuf[8];
        } else {        /* mpeg1 */
                for (buf = inbuf + 6; *buf == 0xff; buf++)
-                       if (buf == inbuf + 6 + 16) {
-                               break;
-                       }
+                       if (buf == inbuf + 6 + 16) {
+                               break;
+                       }
                if ((*buf & 0xc0) == 0x40)
-                       buf += 2;
+                       buf += 2;
                skip = mpeg1_skip_table [*buf >> 4];
                if (skip == 5 || skip == 10) pts = buf;
                else pts = NULL;
@@ -529,9 +529,9 @@ static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_t
        pic->picture_header = 0;
        pic->sequence_header_data
                = ( INIT_HORIZONTAL_SIZE << 20 )
-                       | ( INIT_VERTICAL_SIZE << 8 )
-                       | ( INIT_ASPECT_RATIO << 4 )
-                       | ( INIT_FRAME_RATE );
+                       | ( INIT_VERTICAL_SIZE << 8 )
+                       | ( INIT_ASPECT_RATIO << 4 )
+                       | ( INIT_FRAME_RATE );
        pic->mpeg1_flag = 0;
        pic->vinfo.horizontal_size
                = INIT_DISP_HORIZONTAL_SIZE;
index 95ea509..4a08c4a 100644 (file)
@@ -92,6 +92,7 @@ static DECLARE_MUTEX(frontend_mutex);
 
 struct dvb_frontend_private {
 
+       /* thread/frontend values */
        struct dvb_device *dvbdev;
        struct dvb_frontend_parameters parameters;
        struct dvb_fe_events events;
@@ -100,20 +101,25 @@ struct dvb_frontend_private {
        wait_queue_head_t wait_queue;
        pid_t thread_pid;
        unsigned long release_jiffies;
-       int state;
-       int bending;
-       int lnb_drift;
-       int inversion;
-       int auto_step;
-       int auto_sub_step;
-       int started_auto_step;
-       int min_delay;
-       int max_drift;
-       int step_size;
-       int exit;
-       int wakeup;
+       unsigned int exit;
+       unsigned int wakeup;
        fe_status_t status;
-       fe_sec_tone_mode_t tone;
+       unsigned long tune_mode_flags;
+       unsigned int delay;
+
+       /* swzigzag values */
+       unsigned int state;
+       unsigned int bending;
+       int lnb_drift;
+       unsigned int inversion;
+       unsigned int auto_step;
+       unsigned int auto_sub_step;
+       unsigned int started_auto_step;
+       unsigned int min_delay;
+       unsigned int max_drift;
+       unsigned int step_size;
+       int quality;
+       unsigned int check_wrapped;
 };
 
 
@@ -208,21 +214,21 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
                fe->ops->init(fe);
 }
 
-static void update_delay(int *quality, int *delay, int min_delay, int locked)
+static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
 {
-           int q2;
+       int q2;
 
-           dprintk ("%s\n", __FUNCTION__);
+       dprintk ("%s\n", __FUNCTION__);
 
-           if (locked)
-                     (*quality) = (*quality * 220 + 36*256) / 256;
-           else
-                     (*quality) = (*quality * 220 + 0) / 256;
+       if (locked)
+               (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
+       else
+               (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
 
-           q2 = *quality - 128;
-           q2 *= q2;
+       q2 = fepriv->quality - 128;
+       q2 *= q2;
 
-           *delay = min_delay + q2 * HZ / (128*128);
+       fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
 }
 
 /**
@@ -232,7 +238,7 @@ static void update_delay(int *quality, int *delay, int min_delay, int locked)
  * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
  * @returns Number of complete iterations that have been performed.
  */
-static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
+static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
 {
        int autoinversion;
        int ready = 0;
@@ -321,6 +327,129 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
        return 0;
 }
 
+static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+{
+       fe_status_t s;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+       /* if we've got no parameters, just keep idling */
+       if (fepriv->state & FESTATE_IDLE) {
+               fepriv->delay = 3*HZ;
+               fepriv->quality = 0;
+               return;
+       }
+
+       /* 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);
+                       fepriv->state = FESTATE_TUNED;
+               }
+               fepriv->delay = 3*HZ;
+               fepriv->quality = 0;
+               return;
+       }
+
+       /* get the frontend status */
+       if (fepriv->state & FESTATE_RETUNE) {
+               s = 0;
+       } else {
+               if (fe->ops->read_status)
+                       fe->ops->read_status(fe, &s);
+               if (s != fepriv->status) {
+                       dvb_frontend_add_event(fe, s);
+                       fepriv->status = s;
+               }
+       }
+
+       /* if we're not tuned, and we have a lock, move to the TUNED state */
+       if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+               fepriv->state = FESTATE_TUNED;
+
+               /* if we're tuned, then we have determined the correct inversion */
+               if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+                   (fepriv->parameters.inversion == INVERSION_AUTO)) {
+                       fepriv->parameters.inversion = fepriv->inversion;
+               }
+               return;
+       }
+
+       /* if we are tuned already, check we're still locked */
+       if (fepriv->state & FESTATE_TUNED) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+               /* we're tuned, and the lock is still good... */
+               if (s & FE_HAS_LOCK) {
+                       return;
+               } else { /* if we _WERE_ tuned, but now don't have a lock */
+                       fepriv->state = FESTATE_ZIGZAG_FAST;
+                       fepriv->started_auto_step = fepriv->auto_step;
+                       fepriv->check_wrapped = 0;
+               }
+       }
+
+       /* 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)) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+               return;
+       }
+
+       /* don't do anything if we're in the DISEQC state, since this
+        * might be someone with a motorized dish controlled by DISEQC.
+        * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
+       if (fepriv->state & FESTATE_DISEQC) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+               return;
+       }
+
+       /* if we're in the RETUNE state, set everything up for a brand
+        * new scan, keeping the current inversion setting, as the next
+        * tune is _very_ likely to require the same */
+       if (fepriv->state & FESTATE_RETUNE) {
+               fepriv->lnb_drift = 0;
+               fepriv->auto_step = 0;
+               fepriv->auto_sub_step = 0;
+               fepriv->started_auto_step = 0;
+               fepriv->check_wrapped = 0;
+       }
+
+       /* fast zigzag. */
+       if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
+               fepriv->delay = fepriv->min_delay;
+
+               /* peform a tune */
+               if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
+                       /* OK, if we've run out of trials at the fast speed.
+                        * Drop back to slow for the _next_ attempt */
+                       fepriv->state = FESTATE_SEARCHING_SLOW;
+                       fepriv->started_auto_step = fepriv->auto_step;
+                       return;
+               }
+               fepriv->check_wrapped = 1;
+
+               /* if we've just retuned, enter the ZIGZAG_FAST state.
+                * This ensures we cannot return from an
+                * FE_SET_FRONTEND ioctl before the first frontend tune
+                * occurs */
+               if (fepriv->state & FESTATE_RETUNE) {
+                       fepriv->state = FESTATE_TUNING_FAST;
+               }
+       }
+
+       /* slow zigzag */
+       if (fepriv->state & FESTATE_SEARCHING_SLOW) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+               /* Note: don't bother checking for wrapping; we stay in this
+                * state until we get a lock */
+               dvb_frontend_swzigzag_autotune(fe, 0);
+       }
+}
+
 static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 {
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
@@ -330,7 +459,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
 
        if (fepriv->dvbdev->writers == 1)
                if (time_after(jiffies, fepriv->release_jiffies +
-                                       dvb_shutdown_timeout * HZ))
+                                 dvb_shutdown_timeout * HZ))
                        return 1;
 
        return 0;
@@ -355,18 +484,14 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
        wake_up_interruptible(&fepriv->wait_queue);
 }
 
-/*
- * FIXME: use linux/kthread.h
- */
 static int dvb_frontend_thread(void *data)
 {
        struct dvb_frontend *fe = data;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        unsigned long timeout;
        char name [15];
-       int quality = 0, delay = 3*HZ;
        fe_status_t s;
-       int check_wrapped = 0;
+       struct dvb_frontend_parameters *params;
 
        dprintk("%s\n", __FUNCTION__);
 
@@ -377,6 +502,9 @@ static int dvb_frontend_thread(void *data)
        sigfillset(&current->blocked);
        unlock_kernel();
 
+       fepriv->check_wrapped = 0;
+       fepriv->quality = 0;
+       fepriv->delay = 3*HZ;
        fepriv->status = 0;
        dvb_frontend_init(fe);
        fepriv->wakeup = 0;
@@ -386,7 +514,7 @@ static int dvb_frontend_thread(void *data)
 
                timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
                                                           dvb_frontend_should_wakeup(fe),
-                                                          delay);
+                                                          fepriv->delay);
                if (0 != dvb_frontend_is_exiting(fe)) {
                        /* got signal or quitting */
                        break;
@@ -397,108 +525,22 @@ static int dvb_frontend_thread(void *data)
                if (down_interruptible(&fepriv->sem))
                        break;
 
-               /* if we've got no parameters, just keep idling */
-               if (fepriv->state & FESTATE_IDLE) {
-                       delay = 3*HZ;
-                       quality = 0;
-                       continue;
-               }
+               /* do an iteration of the tuning loop */
+               if (fe->ops->tune) {
+                       /* have we been asked to retune? */
+                       params = NULL;
+                       if (fepriv->state & FESTATE_RETUNE) {
+                               params = &fepriv->parameters;
+                               fepriv->state = FESTATE_TUNED;
+                       }
 
-               /* get the frontend status */
-               if (fepriv->state & FESTATE_RETUNE) {
-                       s = 0;
-               } else {
-                       if (fe->ops->read_status)
-                               fe->ops->read_status(fe, &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;
                        }
-               }
-               /* if we're not tuned, and we have a lock, move to the TUNED state */
-               if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-                       fepriv->state = FESTATE_TUNED;
-
-                       /* if we're tuned, then we have determined the correct inversion */
-                       if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
-                           (fepriv->parameters.inversion == INVERSION_AUTO)) {
-                               fepriv->parameters.inversion = fepriv->inversion;
-                       }
-                       continue;
-               }
-
-               /* if we are tuned already, check we're still locked */
-               if (fepriv->state & FESTATE_TUNED) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-
-                       /* we're tuned, and the lock is still good... */
-                       if (s & FE_HAS_LOCK)
-                               continue;
-                       else { /* if we _WERE_ tuned, but now don't have a lock */
-                               fepriv->state = FESTATE_ZIGZAG_FAST;
-                               fepriv->started_auto_step = fepriv->auto_step;
-                               check_wrapped = 0;
-                       }
-               }
-
-               /* 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)) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-                       continue;
-               }
-
-               /* don't do anything if we're in the DISEQC state, since this
-                * might be someone with a motorized dish controlled by DISEQC.
-                * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
-               if (fepriv->state & FESTATE_DISEQC) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-                       continue;
-               }
-
-               /* if we're in the RETUNE state, set everything up for a brand
-                * new scan, keeping the current inversion setting, as the next
-                * tune is _very_ likely to require the same */
-               if (fepriv->state & FESTATE_RETUNE) {
-                       fepriv->lnb_drift = 0;
-                       fepriv->auto_step = 0;
-                       fepriv->auto_sub_step = 0;
-                       fepriv->started_auto_step = 0;
-                       check_wrapped = 0;
-               }
-
-               /* fast zigzag. */
-               if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
-                       delay = fepriv->min_delay;
-
-                       /* peform a tune */
-                       if (dvb_frontend_autotune(fe, check_wrapped)) {
-                               /* OK, if we've run out of trials at the fast speed.
-                                * Drop back to slow for the _next_ attempt */
-                               fepriv->state = FESTATE_SEARCHING_SLOW;
-                               fepriv->started_auto_step = fepriv->auto_step;
-                               continue;
-                       }
-                       check_wrapped = 1;
-
-                       /* if we've just retuned, enter the ZIGZAG_FAST state.
-                        * This ensures we cannot return from an
-                        * FE_SET_FRONTEND ioctl before the first frontend tune
-                        * occurs */
-                       if (fepriv->state & FESTATE_RETUNE) {
-                               fepriv->state = FESTATE_TUNING_FAST;
-                       }
-               }
-
-               /* slow zigzag */
-               if (fepriv->state & FESTATE_SEARCHING_SLOW) {
-                       update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
-
-                       /* Note: don't bother checking for wrapping; we stay in this
-                        * state until we get a lock */
-                       dvb_frontend_autotune(fe, 0);
+               } else {
+                       dvb_frontend_swzigzag(fe);
                }
        }
 
@@ -733,7 +775,6 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
-                       fepriv->tone = (fe_sec_tone_mode_t) parg;
                }
                break;
 
@@ -747,7 +788,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
        case FE_DISHNETWORK_SEND_LEGACY_CMD:
                if (fe->ops->dishnetwork_send_legacy_command) {
-                       err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
+                       err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
                } else if (fe->ops->set_voltage) {
@@ -767,13 +808,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                         * initialization, so parg is 8 bits and does not
                         * include the initialization or start bit
                         */
-                       unsigned int cmd = ((unsigned int) parg) << 1;
+                       unsigned long cmd = ((unsigned long) parg) << 1;
                        struct timeval nexttime;
                        struct timeval tv[10];
                        int i;
                        u8 last = 1;
                        if (dvb_frontend_debug)
-                               printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd);
+                               printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd);
                        do_gettimeofday(&nexttime);
                        if (dvb_frontend_debug)
                                memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -814,7 +855,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
        case FE_ENABLE_HIGH_LNB_VOLTAGE:
                if (fe->ops->enable_high_lnb_voltage)
-                       err = fe->ops->enable_high_lnb_voltage(fe, (int) parg);
+                       err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
                break;
 
        case FE_SET_FRONTEND: {
@@ -891,6 +932,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
                }
                break;
+
+       case FE_SET_FRONTEND_TUNE_MODE:
+               fepriv->tune_mode_flags = (unsigned long) parg;
+               break;
        };
 
        up (&fepriv->sem);
@@ -932,6 +977,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
 
                /*  empty event queue */
                fepriv->events.eventr = fepriv->events.eventw = 0;
+
+               /* normal tune mode when opened R/W */
+               fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
        }
 
        return ret;
@@ -990,7 +1038,6 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
        init_MUTEX (&fepriv->events.sem);
        fe->dvb = dvb;
        fepriv->inversion = INVERSION_OFF;
-       fepriv->tone = SEC_TONE_OFF;
 
        printk ("DVB: registering frontend %i (%s)...\n",
                fe->dvb->num,
index 1e0840d..70a6d14 100644 (file)
@@ -58,10 +58,19 @@ struct dvb_frontend_ops {
        int (*init)(struct dvb_frontend* fe);
        int (*sleep)(struct dvb_frontend* fe);
 
+       /* if this is set, it overrides the default swzigzag */
+       int (*tune)(struct dvb_frontend* fe,
+                   struct dvb_frontend_parameters* params,
+                   unsigned int mode_flags,
+                   int *delay,
+                   fe_status_t *status);
+
+       /* these two are only used for the swzigzag code */
        int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-       int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
        int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
 
+       int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
        int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
        int (*read_ber)(struct dvb_frontend* fe, u32* ber);
        int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
@@ -74,8 +83,9 @@ struct dvb_frontend_ops {
        int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
        int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
        int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
-       int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg);
-       int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+       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);
 };
 
 #define MAX_EVENT 8
index 86bba81..6711eb6 100644 (file)
@@ -1222,7 +1222,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
        return if_num;
 }
 
-static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num)
+static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
 {
        struct net_device *net = dvbnet->device[num];
        struct dvb_net_priv *priv;
@@ -1296,9 +1296,9 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
 
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               if ((unsigned int) parg >= DVB_NET_DEVICES_MAX)
+               if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
                        return -EINVAL;
-               ret = dvb_net_remove_if(dvbnet, (unsigned int) parg);
+               ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
                if (!ret)
                        module_put(dvbdev->adapter->module);
                return ret;
index 283c6e9..77ad241 100644 (file)
@@ -112,10 +112,10 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in
        split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
        if (split > 0) {
                if (!usermem)
-                       memcpy(buf, rbuf->data+rbuf->pread, split);
+                       memcpy(buf, rbuf->data+rbuf->pread, split);
                else
-                       if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
-                               return -EFAULT;
+                       if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+                               return -EFAULT;
                buf += split;
                todo -= split;
                rbuf->pread = 0;
@@ -124,7 +124,7 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in
                memcpy(buf, rbuf->data+rbuf->pread, todo);
        else
                if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
-                       return -EFAULT;
+                       return -EFAULT;
 
        rbuf->pread = (rbuf->pread + todo) % rbuf->size;
 
@@ -167,7 +167,7 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le
 }
 
 ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-                               int offset, u8* buf, size_t len, int usermem)
+                               int offset, u8* buf, size_t len, int usermem)
 {
        size_t todo;
        size_t split;
@@ -183,10 +183,10 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
        split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
        if (split > 0) {
                if (!usermem)
-                       memcpy(buf, rbuf->data+idx, split);
+                       memcpy(buf, rbuf->data+idx, split);
                else
-                       if (copy_to_user(buf, rbuf->data+idx, split))
-                               return -EFAULT;
+                       if (copy_to_user(buf, rbuf->data+idx, split))
+                               return -EFAULT;
                buf += split;
                todo -= split;
                idx = 0;
@@ -195,7 +195,7 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
                memcpy(buf, rbuf->data+idx, todo);
        else
                if (copy_to_user(buf, rbuf->data+idx, todo))
-                       return -EFAULT;
+                       return -EFAULT;
 
        return len;
 }
@@ -209,12 +209,12 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
        // clean up disposed packets
        while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
                if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
-                       pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
-                       pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
-                       DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
+                       pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
+                       pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
+                       DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
                } else {
-                       // first packet is not disposed, so we stop cleaning now
-                       break;
+                       // first packet is not disposed, so we stop cleaning now
+                       break;
                }
        }
 }
@@ -242,8 +242,8 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t*
                curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
 
                if (curpktstatus == PKT_READY) {
-                       *pktlen = curpktlen;
-                       return idx;
+                       *pktlen = curpktlen;
+                       return idx;
                }
 
                consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
index fa476f6..6d25609 100644 (file)
@@ -106,7 +106,7 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
 ** returns number of bytes transferred or -EFAULT
 */
 extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
-                                  size_t len, int usermem);
+                                  size_t len, int usermem);
 
 
 /* write routines & macros */
@@ -121,7 +121,7 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
 ** returns number of bytes transferred or -EFAULT
 */
 extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
-                                   size_t len);
+                                   size_t len);
 
 
 /**
@@ -133,7 +133,7 @@ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
  * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
  */
 extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
-                                       size_t len);
+                                       size_t len);
 
 /**
  * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
@@ -149,7 +149,7 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
  * returns Number of bytes read, or -EFAULT.
  */
 extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-                                      int offset, u8* buf, size_t len, int usermem);
+                                      int offset, u8* buf, size_t len, int usermem);
 
 /**
  * Dispose of a packet in the ring buffer.
index a4aee86..06b696e 100644 (file)
@@ -92,10 +92,10 @@ static int dvb_device_open(struct inode *inode, struct file *file)
                old_fops = file->f_op;
                file->f_op = fops_get(dvbdev->fops);
                if(file->f_op->open)
-                       err = file->f_op->open(inode,file);
+                       err = file->f_op->open(inode,file);
                if (err) {
-                       fops_put(file->f_op);
-                       file->f_op = fops_get(old_fops);
+                       fops_put(file->f_op);
+                       file->f_op = fops_get(old_fops);
                }
                fops_put(old_fops);
                return err;
@@ -356,18 +356,18 @@ int dvb_usercopy(struct inode *inode, struct file *file,
        case _IOC_WRITE:
        case (_IOC_WRITE | _IOC_READ):
                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
-                       parg = sbuf;
+                       parg = sbuf;
                } else {
-                       /* too big to allocate from stack */
-                       mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
-                       if (NULL == mbuf)
-                               return -ENOMEM;
-                       parg = mbuf;
+                       /* too big to allocate from stack */
+                       mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+                       if (NULL == mbuf)
+                               return -ENOMEM;
+                       parg = mbuf;
                }
 
                err = -EFAULT;
                if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
-                       goto out;
+                       goto out;
                break;
        }
 
@@ -384,7 +384,7 @@ int dvb_usercopy(struct inode *inode, struct file *file,
        case _IOC_READ:
        case (_IOC_WRITE | _IOC_READ):
                if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
-                       err = -EFAULT;
+                       err = -EFAULT;
                break;
        }
 
index 0cc6e4a..74ed585 100644 (file)
@@ -97,7 +97,7 @@ we simply define out own dvb_usercopy(), which will hopefully become
 generic_usercopy()  someday... */
 
 extern int dvb_usercopy(struct inode *inode, struct file *file,
-                           unsigned int cmd, unsigned long arg,
+                           unsigned int cmd, unsigned long arg,
                            int (*func)(struct inode *inode, struct file *file,
                            unsigned int cmd, void *arg));
 
index 54e2b29..90a69d3 100644 (file)
@@ -37,16 +37,16 @@ config DVB_USB_DIBUSB_MB
          DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
 
          Devices supported by this driver:
-           TwinhanDTV USB-Ter (VP7041)
-           TwinhanDTV Magic Box (VP7041e)
-           KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
-           Hama DVB-T USB1.1-Box
-           DiBcom USB1.1 reference devices (non-public)
-           Ultima Electronic/Artec T1 USB TVBOX
+           Artec T1 USB1.1 boxes
+           Avermedia AverTV DVBT USB1.1
            Compro Videomate DVB-U2000 - DVB-T USB
+           DiBcom USB1.1 reference devices (non-public)
            Grandtec DVB-T USB
-           Avermedia AverTV DVBT USB1.1
-           Artec T1 USB1.1 boxes
+           Hama DVB-T USB1.1-Box
+           KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
+           TwinhanDTV Magic Box (VP7041e)
+           TwinhanDTV USB-Ter (VP7041)
+           Ultima Electronic/Artec T1 USB TVBOX
 
          The VP7041 seems to be identical to "CTS Portable" (Chinese
          Television System).
@@ -54,6 +54,12 @@ config DVB_USB_DIBUSB_MB
          Say Y if you own such a device and want to use it. You should build it as
          a module.
 
+config DVB_USB_DIBUSB_MB_FAULTY
+       bool "Support faulty USB IDs"
+       depends on DVB_USB_DIBUSB_MB
+       help
+         Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
+
 config DVB_USB_DIBUSB_MC
        tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
        depends on DVB_USB
@@ -63,8 +69,8 @@ config DVB_USB_DIBUSB_MC
          DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
 
          Devices supported by this driver:
-           DiBcom USB2.0 reference devices (non-public)
            Artec T1 USB2.0 boxes
+           DiBcom USB2.0 reference devices (non-public)
 
          Say Y if you own such a device and want to use it. You should build it as
          a module.
index d05fab0..358ed15 100644 (file)
  * design, so it can be reused for the "analogue-only" device (if it will
  * appear at all).
  *
- * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue
- * part
+ * TODO: Use the cx25840-driver for the analogue part
  *
  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net)
+ * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
  *
  *     This program is free software; you can redistribute it and/or modify it
  *     under the terms of the GNU General Public License as published by the Free
@@ -25,6 +26,9 @@
 #include "cxusb.h"
 
 #include "cx22702.h"
+#include "lgdt330x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
 
 /* debug */
 int dvb_usb_cxusb_debug;
@@ -156,6 +160,99 @@ static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
        return 0;
 }
 
+static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       u8 ircode[4];
+       int i;
+
+       cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
+
+       *event = 0;
+       *state = REMOTE_NO_KEY_PRESSED;
+
+       for (i = 0; i < d->props.rc_key_map_size; i++) {
+               if (keymap[i].custom == ircode[2] &&
+                   keymap[i].data == ircode[3]) {
+                       *event = keymap[i].event;
+                       *state = REMOTE_KEY_PRESSED;
+
+                       return 0;
+               }
+       }
+
+       return 0;
+}
+
+struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
+       { 0xfe, 0x02, KEY_TV },
+       { 0xfe, 0x0e, KEY_MP3 },
+       { 0xfe, 0x1a, KEY_DVD },
+       { 0xfe, 0x1e, KEY_FAVORITES },
+       { 0xfe, 0x16, KEY_SETUP },
+       { 0xfe, 0x46, KEY_POWER2 },
+       { 0xfe, 0x0a, KEY_EPG },
+       { 0xfe, 0x49, KEY_BACK },
+       { 0xfe, 0x4d, KEY_MENU },
+       { 0xfe, 0x51, KEY_UP },
+       { 0xfe, 0x5b, KEY_LEFT },
+       { 0xfe, 0x5f, KEY_RIGHT },
+       { 0xfe, 0x53, KEY_DOWN },
+       { 0xfe, 0x5e, KEY_OK },
+       { 0xfe, 0x59, KEY_INFO },
+       { 0xfe, 0x55, KEY_TAB },
+       { 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */
+       { 0xfe, 0x12, KEY_NEXTSONG },   /* Skip */
+       { 0xfe, 0x42, KEY_ENTER  },     /* Windows/Start */
+       { 0xfe, 0x15, KEY_VOLUMEUP },
+       { 0xfe, 0x05, KEY_VOLUMEDOWN },
+       { 0xfe, 0x11, KEY_CHANNELUP },
+       { 0xfe, 0x09, KEY_CHANNELDOWN },
+       { 0xfe, 0x52, KEY_CAMERA },
+       { 0xfe, 0x5a, KEY_TUNER },      /* Live */
+       { 0xfe, 0x19, KEY_OPEN },
+       { 0xfe, 0x0b, KEY_1 },
+       { 0xfe, 0x17, KEY_2 },
+       { 0xfe, 0x1b, KEY_3 },
+       { 0xfe, 0x07, KEY_4 },
+       { 0xfe, 0x50, KEY_5 },
+       { 0xfe, 0x54, KEY_6 },
+       { 0xfe, 0x48, KEY_7 },
+       { 0xfe, 0x4c, KEY_8 },
+       { 0xfe, 0x58, KEY_9 },
+       { 0xfe, 0x13, KEY_ANGLE },      /* Aspect */
+       { 0xfe, 0x03, KEY_0 },
+       { 0xfe, 0x1f, KEY_ZOOM },
+       { 0xfe, 0x43, KEY_REWIND },
+       { 0xfe, 0x47, KEY_PLAYPAUSE },
+       { 0xfe, 0x4f, KEY_FASTFORWARD },
+       { 0xfe, 0x57, KEY_MUTE },
+       { 0xfe, 0x0d, KEY_STOP },
+       { 0xfe, 0x01, KEY_RECORD },
+       { 0xfe, 0x4e, KEY_POWER },
+};
+
+static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
+{
+       static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x38 };
+       static u8 reset []         = { RESET,      0x80 };
+       static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+       static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0x20 };
+       static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+       static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+       mt352_write(fe, clock_config,   sizeof(clock_config));
+       udelay(200);
+       mt352_write(fe, reset,          sizeof(reset));
+       mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+       mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+       mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+       mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+       return 0;
+}
+
 struct cx22702_config cxusb_cx22702_config = {
        .demod_address = 0x63,
 
@@ -165,17 +262,47 @@ struct cx22702_config cxusb_cx22702_config = {
        .pll_set  = dvb_usb_pll_set_i2c,
 };
 
+struct lgdt330x_config cxusb_lgdt330x_config = {
+       .demod_address = 0x0e,
+       .demod_chip    = LGDT3303,
+       .pll_set       = dvb_usb_pll_set_i2c,
+};
+
+struct mt352_config cxusb_dee1601_config = {
+       .demod_address = 0x0f,
+       .demod_init    = cxusb_dee1601_demod_init,
+       .pll_set       = dvb_usb_pll_set,
+};
+
 /* Callbacks for DVB USB */
-static int cxusb_tuner_attach(struct dvb_usb_device *d)
+static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
 {
        u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
        d->pll_addr = 0x61;
-       memcpy(d->pll_init,bpll,4);
+       memcpy(d->pll_init, bpll, 4);
        d->pll_desc = &dvb_pll_fmd1216me;
        return 0;
 }
 
-static int cxusb_frontend_attach(struct dvb_usb_device *d)
+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;
+       return 0;
+}
+
+static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
+{
+       d->pll_addr = 0x61;
+       d->pll_desc = &dvb_pll_thomson_dtt7579;
+       return 0;
+}
+
+static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d)
 {
        u8 b;
        if (usb_set_interface(d->udev,0,6) < 0)
@@ -189,22 +316,84 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d)
        return -EIO;
 }
 
+static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d)
+{
+       if (usb_set_interface(d->udev,0,7) < 0)
+               err("set interface failed");
+
+       cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+
+       if ((d->fe = lgdt330x_attach(&cxusb_lgdt330x_config, &d->i2c_adap)) != NULL)
+               return 0;
+
+       return -EIO;
+}
+
+static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
+{
+       if (usb_set_interface(d->udev,0,0) < 0)
+               err("set interface failed");
+
+       cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+
+       if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+               return 0;
+
+       return -EIO;
+}
+
+/*
+ * DViCO bluebird firmware needs the "warm" product ID to be patched into the
+ * firmware file before download.
+ */
+
+#define BLUEBIRD_01_ID_OFFSET 6638
+static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw)
+{
+       if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
+               return -EINVAL;
+
+       if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
+           fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
+
+               /* FIXME: are we allowed to change the fw-data ? */
+               fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1;
+               fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8;
+
+               return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2);
+       }
+
+       return -EINVAL;
+}
+
 /* DVB USB Driver stuff */
-static struct dvb_usb_properties cxusb_properties;
+static struct dvb_usb_properties cxusb_medion_properties;
+static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties;
+static struct dvb_usb_properties cxusb_bluebird_dee1601_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE,NULL);
+       if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
+               dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
+               dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0) {
+               return 0;
+       }
+
+       return -EINVAL;
 }
 
 static struct usb_device_id cxusb_table [] = {
                { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
+               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
+               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) },
+               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) },
                {}              /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
 
-static struct dvb_usb_properties cxusb_properties = {
+static struct dvb_usb_properties cxusb_medion_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
 
        .usb_ctrl = CYPRESS_FX2,
@@ -213,8 +402,8 @@ static struct dvb_usb_properties cxusb_properties = {
 
        .streaming_ctrl   = cxusb_streaming_ctrl,
        .power_ctrl       = cxusb_power_ctrl,
-       .frontend_attach  = cxusb_frontend_attach,
-       .tuner_attach     = cxusb_tuner_attach,
+       .frontend_attach  = cxusb_cx22702_frontend_attach,
+       .tuner_attach     = cxusb_fmd1216me_tuner_attach,
 
        .i2c_algo         = &cxusb_i2c_algo,
 
@@ -240,6 +429,91 @@ static struct dvb_usb_properties cxusb_properties = {
        }
 };
 
+static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl          = DEVICE_SPECIFIC,
+       .firmware          = "dvb-usb-bluebird-01.fw",
+       .download_firmware = bluebird_patch_dvico_firmware_download,
+       /* use usb alt setting 0 for EP4 transfer (dvb-t),
+          use usb alt setting 7 for EP2 transfer (atsc) */
+
+       .size_of_priv     = sizeof(struct cxusb_state),
+
+       .streaming_ctrl   = cxusb_streaming_ctrl,
+       .power_ctrl       = cxusb_power_ctrl,
+       .frontend_attach  = cxusb_lgdt330x_frontend_attach,
+       .tuner_attach     = cxusb_lgh064f_tuner_attach,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 5,
+               .endpoint = 0x02,
+               .u = {
+                       .bulk = {
+                               .buffersize = 8192,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "DViCO FusionHDTV5 USB Gold",
+                       { &cxusb_table[1], NULL },
+                       { &cxusb_table[2], NULL },
+               },
+       }
+};
+
+static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl          = DEVICE_SPECIFIC,
+       .firmware          = "dvb-usb-bluebird-01.fw",
+       .download_firmware = bluebird_patch_dvico_firmware_download,
+       /* use usb alt setting 0 for EP4 transfer (dvb-t),
+          use usb alt setting 7 for EP2 transfer (atsc) */
+
+       .size_of_priv     = sizeof(struct cxusb_state),
+
+       .streaming_ctrl   = cxusb_streaming_ctrl,
+       .power_ctrl       = cxusb_power_ctrl,
+       .frontend_attach  = cxusb_dee1601_frontend_attach,
+       .tuner_attach     = cxusb_dee1601_tuner_attach,
+
+       .i2c_algo         = &cxusb_i2c_algo,
+
+       .rc_interval      = 150,
+       .rc_key_map       = dvico_mce_rc_keys,
+       .rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+       .rc_query         = cxusb_rc_query,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 5,
+               .endpoint = 0x04,
+               .u = {
+                       .bulk = {
+                               .buffersize = 8192,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "DViCO FusionHDTV DVB-T Dual USB",
+                       { &cxusb_table[3], NULL },
+                       { &cxusb_table[4], NULL },
+               },
+       }
+};
+
 static struct usb_driver cxusb_driver = {
        .name           = "dvb_usb_cxusb",
        .probe          = cxusb_probe,
index 135c2a8..087c994 100644 (file)
@@ -21,6 +21,8 @@ extern int dvb_usb_cxusb_debug;
 #define CMD_STREAMING_ON  0x36
 #define CMD_STREAMING_OFF 0x37
 
+#define CMD_GET_IR_CODE   0x47
+
 #define CMD_ANALOG        0x50
 #define CMD_DIGITAL       0x51
 
index 52ac3e5..dd5a131 100644 (file)
@@ -65,11 +65,11 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
                d->tuner_pass_ctrl(d->fe,0,msg[0].addr);
 
        if (b2[0] == 0xfe) {
-               info("this device has the Thomson Cable onboard. Which is default.");
+               info("This device has the Thomson Cable onboard. Which is default.");
                dibusb_thomson_tuner_attach(d);
        } else {
                u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
-               info("this device has the Panasonic ENV77H11D5 onboard.");
+               info("This device has the Panasonic ENV77H11D5 onboard.");
                d->pll_addr = 0x60;
                memcpy(d->pll_init,bpll,4);
                d->pll_desc = &dvb_pll_tda665x;
@@ -98,15 +98,15 @@ static int dibusb_probe(struct usb_interface *intf,
 
 /* do not change the order of the ID table */
 static struct usb_device_id dibusb_dib3000mb_table [] = {
-/* 00 */       { USB_DEVICE(USB_VID_WIDEVIEW,          USB_PID_AVERMEDIA_DVBT_USB_COLD)},
-/* 01 */       { USB_DEVICE(USB_VID_WIDEVIEW,          USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+/* 00 */       { USB_DEVICE(USB_VID_WIDEVIEW,          USB_PID_AVERMEDIA_DVBT_USB_COLD) },
+/* 01 */       { USB_DEVICE(USB_VID_WIDEVIEW,          USB_PID_AVERMEDIA_DVBT_USB_WARM) },
 /* 02 */       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_COLD) },
 /* 03 */       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_WARM) },
 /* 04 */       { USB_DEVICE(USB_VID_COMPRO_UNK,        USB_PID_COMPRO_DVBU2000_UNK_COLD) },
 /* 05 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_COLD) },
 /* 06 */       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_WARM) },
-/* 07 */       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_COLD) },
-/* 08 */       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_WARM) },
+/* 07 */       { USB_DEVICE(USB_VID_EMPIA,             USB_PID_KWORLD_VSTREAM_COLD) },
+/* 08 */       { USB_DEVICE(USB_VID_EMPIA,             USB_PID_KWORLD_VSTREAM_WARM) },
 /* 09 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_COLD) },
 /* 10 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_WARM) },
 /* 11 */       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_DIBCOM_MOD3000_COLD) },
@@ -117,27 +117,34 @@ static struct usb_device_id dibusb_dib3000mb_table [] = {
 /* 16 */       { USB_DEVICE(USB_VID_VISIONPLUS,        USB_PID_TWINHAN_VP7041_WARM) },
 /* 17 */       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_COLD) },
 /* 18 */       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_WARM) },
-/* 19 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
-/* 20 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
-/* 21 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
-/* 22 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
+/* 19 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
+/* 20 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
+/* 21 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+/* 22 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
 /* 23 */       { USB_DEVICE(USB_VID_ADSTECH,           USB_PID_ADSTECH_USB2_COLD) },
 
 /* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
 /* 24 */       { USB_DEVICE(USB_VID_ADSTECH,           USB_PID_ADSTECH_USB2_WARM) },
-/* 25 */       { USB_DEVICE(USB_VID_KYE,                       USB_PID_KYE_DVB_T_COLD) },
-/* 26 */       { USB_DEVICE(USB_VID_KYE,                       USB_PID_KYE_DVB_T_WARM) },
+/* 25 */       { USB_DEVICE(USB_VID_KYE,               USB_PID_KYE_DVB_T_COLD) },
+/* 26 */       { USB_DEVICE(USB_VID_KYE,               USB_PID_KYE_DVB_T_WARM) },
 
 /* 27 */       { USB_DEVICE(USB_VID_KWORLD,            USB_PID_KWORLD_VSTREAM_COLD) },
 
-/* 28 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,         USB_PID_ULTIMA_TVBOX_USB2_COLD) },
-/* 29 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,         USB_PID_ULTIMA_TVBOX_USB2_WARM) },
+/* 28 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 29 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) },
 
-// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+/*
+ * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
+ *      we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
+ *      have been left on the device. If you don't have such a device but an Artec
+ *      device that's supposed to work with this driver but is not detected by it,
+ *      free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
+ */
 
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
 /* 30 */       { USB_DEVICE(USB_VID_ANCHOR,            USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
 #endif
+
                        { }             /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
@@ -257,7 +264,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
                }
        },
 
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
        .num_device_descs = 2,
 #else
        .num_device_descs = 1,
@@ -267,11 +274,12 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
                        { &dibusb_dib3000mb_table[20], NULL },
                        { &dibusb_dib3000mb_table[21], NULL },
                },
-#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
                {       "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
                        { &dibusb_dib3000mb_table[30], NULL },
                        { NULL },
                },
+               { NULL },
 #endif
        }
 };
@@ -323,6 +331,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
                        { &dibusb_dib3000mb_table[27], NULL },
                        { NULL }
                },
+               { NULL },
        }
 };
 
@@ -369,6 +378,7 @@ static struct dvb_usb_properties artec_t1_usb2_properties = {
                        { &dibusb_dib3000mb_table[28], NULL },
                        { &dibusb_dib3000mb_table[29], NULL },
                },
+               { NULL },
        }
 };
 
index 450417a..e6c55c9 100644 (file)
@@ -32,7 +32,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d,
        sndbuf[1] = vv;
        sndbuf[2] = wo ? wlen : rlen;
 
-       if (!wo) {
+       if (wo) {
                memcpy(&sndbuf[3],wbuf,wlen);
                dvb_usb_generic_write(d,sndbuf,7);
        } else {
index 6e2bac8..130ea7f 100644 (file)
@@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = {
                  .cold_ids = { &dtt200u_usb_table[0], NULL },
                  .warm_ids = { &dtt200u_usb_table[1], NULL },
                },
-               { NULL },
+               { 0 },
        }
 };
 
@@ -160,7 +160,7 @@ static struct dvb_usb_properties wt220u_properties = {
        .pid_filter_count = 15,
 
        .usb_ctrl = CYPRESS_FX2,
-       .firmware = "dvb-usb-wt220u-01.fw",
+       .firmware = "dvb-usb-wt220u-02.fw",
 
        .power_ctrl      = dtt200u_power_ctrl,
        .streaming_ctrl  = dtt200u_streaming_ctrl,
@@ -192,7 +192,7 @@ static struct dvb_usb_properties wt220u_properties = {
                  .cold_ids = { &dtt200u_usb_table[2], NULL },
                  .warm_ids = { &dtt200u_usb_table[3], NULL },
                },
-               { NULL },
+               { 0 },
        }
 };
 
index 6f1f304..005b0a7 100644 (file)
@@ -13,6 +13,7 @@
 #define _DVB_USB_DTT200U_H_
 
 #define DVB_USB_LOG_PREFIX "dtt200u"
+
 #include "dvb-usb.h"
 
 extern int dvb_usb_dtt200u_debug;
@@ -25,15 +26,15 @@ extern int dvb_usb_dtt200u_debug;
  *  88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
  */
 
-#define GET_SPEED            0x00
-#define GET_TUNE_STATUS      0x81
-#define GET_RC_CODE          0x84
-#define GET_CONFIGURATION    0x88
-#define GET_AGC              0x89
-#define GET_SNR              0x8a
-#define GET_VIT_ERR_CNT      0x8c
-#define GET_RS_ERR_CNT       0x8d
-#define GET_RS_UNCOR_BLK_CNT 0x8e
+#define GET_SPEED              0x00
+#define GET_TUNE_STATUS                0x81
+#define GET_RC_CODE            0x84
+#define GET_CONFIGURATION      0x88
+#define GET_AGC                        0x89
+#define GET_SNR                        0x8a
+#define GET_VIT_ERR_CNT                0x8c
+#define GET_RS_ERR_CNT         0x8d
+#define GET_RS_UNCOR_BLK_CNT   0x8e
 
 /* write
  *  01 - init
@@ -44,12 +45,12 @@ extern int dvb_usb_dtt200u_debug;
  *  08 - transfer switch
  */
 
-#define SET_INIT         0x01
-#define SET_RF_FREQ      0x02
-#define SET_BANDWIDTH    0x03
-#define SET_PID_FILTER   0x04
-#define RESET_PID_FILTER 0x05
-#define SET_STREAMING    0x08
+#define SET_INIT               0x01
+#define SET_RF_FREQ            0x02
+#define SET_BANDWIDTH          0x03
+#define SET_PID_FILTER         0x04
+#define RESET_PID_FILTER       0x05
+#define SET_STREAMING          0x08
 
 extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
 
index 7300489..a3460bf 100644 (file)
@@ -24,7 +24,7 @@ extern int dvb_usb_disable_rc_polling;
 #define deb_mem(args...)  dprintk(dvb_usb_debug,0x80,args)
 
 /* commonly used  methods */
-extern int usb_cypress_load_firmware(struct usb_device *, const char *, int);
+extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *);
 
 extern int dvb_usb_urb_submit(struct dvb_usb_device *);
 extern int dvb_usb_urb_kill(struct dvb_usb_device *);
index 5244e39..8535895 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include "dvb-usb-common.h"
 
-#include <linux/firmware.h>
 #include <linux/usb.h>
 
 struct usb_cypress_controller {
@@ -19,9 +18,10 @@ struct usb_cypress_controller {
 };
 
 static struct usb_cypress_controller cypress[] = {
-       { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
-       { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
-       { .id = CYPRESS_FX2,    .name = "Cypress FX2",    .cpu_cs_register = 0xe600 },
+       { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
+       { .id = CYPRESS_AN2135,  .name = "Cypress AN2135",  .cpu_cs_register = 0x7f92 },
+       { .id = CYPRESS_AN2235,  .name = "Cypress AN2235",  .cpu_cs_register = 0x7f92 },
+       { .id = CYPRESS_FX2,     .name = "Cypress FX2",     .cpu_cs_register = 0xe600 },
 };
 
 /*
@@ -30,71 +30,117 @@ static struct usb_cypress_controller cypress[] = {
 static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
 {
        return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
-                       0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
+                       0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
 }
 
-int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type)
+int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
 {
-       const struct firmware *fw = NULL;
-       u16 addr;
-       u8 *b,*p;
-       int ret = 0,i;
+       struct hexline hx;
+       u8 reset;
+       int ret,pos=0;
 
-       if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) {
-               err("did not find the firmware file. (%s) "
-                       "Please see linux/Documentation/dvb/ for more details on firmware-problems.",
-                       filename);
+       /* stop the CPU */
+       reset = 1;
+       if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+               err("could not stop the USB controller CPU.");
+
+       while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
+               deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
+               ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+
+               if (ret != hx.len) {
+                       err("error while transferring firmware "
+                               "(transferred size: %d, block size: %d)",
+                               ret,hx.len);
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+       if (ret < 0) {
+               err("firmware download failed at %d with %d",pos,ret);
                return ret;
        }
 
-       info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name);
-
-       p = kmalloc(fw->size,GFP_KERNEL);
-       if (p != NULL) {
-               u8 reset;
-               /*
-                * you cannot use the fw->data as buffer for
-                * usb_control_msg, a new buffer has to be
-                * created
-                */
-               memcpy(p,fw->data,fw->size);
-
-               /* stop the CPU */
-               reset = 1;
-               if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
-                       err("could not stop the USB controller CPU.");
-               for(i = 0; p[i+3] == 0 && i < fw->size; ) {
-                       b = (u8 *) &p[i];
-                       addr = cpu_to_le16( *((u16 *) &b[1]) );
-
-                       deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]);
-
-                       ret = usb_cypress_writemem(udev,addr,&b[4],b[0]);
-
-                       if (ret != b[0]) {
-                               err("error while transferring firmware "
-                                       "(transferred size: %d, block size: %d)",
-                                       ret,b[0]);
-                               ret = -EINVAL;
-                               break;
-                       }
-                       i += 5 + b[0];
-               }
-               /* length in ret */
-               if (ret > 0)
-                       ret = 0;
+       if (ret == 0) {
                /* restart the CPU */
                reset = 0;
                if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
                        err("could not restart the USB controller CPU.");
                        ret = -EINVAL;
                }
+       } else
+               ret = -EIO;
 
-               kfree(p);
-       } else {
-               ret = -ENOMEM;
+       return ret;
+}
+EXPORT_SYMBOL(usb_cypress_load_firmware);
+
+int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props)
+{
+       int ret;
+       const struct firmware *fw = NULL;
+
+       if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
+               err("did not find the firmware file. (%s) "
+                       "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+                       props->firmware,ret);
+               return ret;
        }
-       release_firmware(fw);
 
+       info("downloading firmware from file '%s'",props->firmware);
+
+       switch (props->usb_ctrl) {
+               case CYPRESS_AN2135:
+               case CYPRESS_AN2235:
+               case CYPRESS_FX2:
+                       ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl);
+                       break;
+               case DEVICE_SPECIFIC:
+                       if (props->download_firmware)
+                               ret = props->download_firmware(udev,fw);
+                       else {
+                               err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
+                               ret = -EINVAL;
+                       }
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+       }
+
+       release_firmware(fw);
        return ret;
 }
+
+int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos)
+{
+       u8 *b = (u8 *) &fw->data[*pos];
+       int data_offs = 4;
+       if (*pos >= fw->size)
+               return 0;
+
+       memset(hx,0,sizeof(struct hexline));
+
+       hx->len  = b[0];
+
+       if ((*pos + hx->len + 4) >= fw->size)
+               return -EINVAL;
+
+       hx->addr = le16_to_cpu( *((u16 *) &b[1]) );
+       hx->type = b[3];
+
+       if (hx->type == 0x04) {
+               /* b[4] and b[5] are the Extended linear address record data field */
+               hx->addr |= (b[4] << 24) | (b[5] << 16);
+/*             hx->len -= 2;
+               data_offs += 2; */
+       }
+       memcpy(hx->data,&b[data_offs],hx->len);
+       hx->chk = b[hx->len + data_offs];
+
+       *pos += hx->len + 5;
+
+       return *pos;
+}
+EXPORT_SYMBOL(dvb_usb_get_hexline);
+
index da97094..9b25453 100644 (file)
@@ -52,9 +52,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
        struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
        int ret = 0;
 
-       /* if there is nothing to initialize */
-       if (d->pll_init[0] == 0x00 && d->pll_init[1] == 0x00 &&
-               d->pll_init[2] == 0x00 && d->pll_init[3] == 0x00)
+       /* if pll_desc is not used */
+       if (d->pll_desc == NULL)
                return 0;
 
        if (d->tuner_pass_ctrl)
@@ -80,6 +79,9 @@ int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep
 {
        struct dvb_usb_device *d = fe->dvb->priv;
 
+       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;
index 6be99e5..d229343 100644 (file)
 #define USB_PID_WINTV_NOVA_T_USB2_COLD         0x9300
 #define USB_PID_WINTV_NOVA_T_USB2_WARM         0x9301
 #define USB_PID_NEBULA_DIGITV                          0x0201
-#define USB_PID_DVICO_BLUEBIRD_LGZ201          0xdb00
-#define USB_PID_DVICO_BLUEBIRD_TH7579          0xdb10
 #define USB_PID_DVICO_BLUEBIRD_LGDT                    0xd820
-#define USB_PID_DVICO_BLUEBIRD_LGZ201_1                0xdb01
-#define USB_PID_DVICO_BLUEBIRD_TH7579_2                0xdb11
+#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD             0xd500
+#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM             0xd501
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD             0xdb00
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM             0xdb01
+#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD             0xdb10
+#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM             0xdb11
+#define USB_PID_DVICO_BLUEBIRD_DEE1601_COLD            0xdb50
+#define USB_PID_DVICO_BLUEBIRD_DEE1601_WARM            0xdb51
 #define USB_PID_MEDION_MD95700                         0x0932
 #define USB_PID_KYE_DVB_T_COLD                         0x701e
 #define USB_PID_KYE_DVB_T_WARM                         0x701f
index dd8e0b9..2e23060 100644 (file)
@@ -138,6 +138,9 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
 
        int ret = -ENOMEM,cold=0;
 
+       if (du != NULL)
+               *du = NULL;
+
        if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
                deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
                return -ENODEV;
@@ -145,38 +148,40 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
 
        if (cold) {
                info("found a '%s' in cold state, will try to load a firmware",desc->name);
-               ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl);
-       } else {
-               info("found a '%s' in warm state.",desc->name);
-               d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
-               if (d == NULL) {
-                       err("no memory for 'struct dvb_usb_device'");
+               ret = dvb_usb_download_firmware(udev,props);
+               if (!props->no_reconnect)
                        return ret;
+       }
+
+       info("found a '%s' in warm state.",desc->name);
+       d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+       if (d == NULL) {
+               err("no memory for 'struct dvb_usb_device'");
+               return ret;
+       }
+       memset(d,0,sizeof(struct dvb_usb_device));
+
+       d->udev = udev;
+       memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
+       d->desc = desc;
+       d->owner = owner;
+
+       if (d->props.size_of_priv > 0) {
+               d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
+               if (d->priv == NULL) {
+                       err("no memory for priv in 'struct dvb_usb_device'");
+                       kfree(d);
+                       return -ENOMEM;
                }
-               memset(d,0,sizeof(struct dvb_usb_device));
-
-               d->udev = udev;
-               memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
-               d->desc = desc;
-               d->owner = owner;
-
-               if (d->props.size_of_priv > 0) {
-                       d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
-                       if (d->priv == NULL) {
-                               err("no memory for priv in 'struct dvb_usb_device'");
-                               kfree(d);
-                               return -ENOMEM;
-                       }
-                       memset(d->priv,0,d->props.size_of_priv);
-               }
+               memset(d->priv,0,d->props.size_of_priv);
+       }
 
-               usb_set_intfdata(intf, d);
+       usb_set_intfdata(intf, d);
 
-               if (du != NULL)
-                       *du = d;
+       if (du != NULL)
+               *du = d;
 
-               ret = dvb_usb_init(d);
-       }
+       ret = dvb_usb_init(d);
 
        if (ret == 0)
                info("%s successfully initialized and connected.",desc->name);
index b4a1a98..dd56839 100644 (file)
@@ -10,8 +10,8 @@
 
 #include <linux/config.h>
 #include <linux/input.h>
-#include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/firmware.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -94,7 +94,11 @@ struct dvb_usb_device;
  * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
  *  download.
  * @firmware: name of the firmware file.
- *
+ * @download_firmware: called to download the firmware when the usb_ctrl is
+ *  DEVICE_SPECIFIC.
+ * @no_reconnect: device doesn't do a reconnect after downloading the firmware,
+    so do the warm initialization right after it
+
  * @size_of_priv: how many bytes shall be allocated for the private field
  *  of struct dvb_usb_device.
  *
@@ -142,11 +146,14 @@ struct dvb_usb_properties {
        int caps;
        int pid_filter_count;
 
-#define CYPRESS_AN2135  0
-#define CYPRESS_AN2235  1
-#define CYPRESS_FX2     2
+#define DEVICE_SPECIFIC 0
+#define CYPRESS_AN2135  1
+#define CYPRESS_AN2235  2
+#define CYPRESS_FX2     3
        int usb_ctrl;
-       const char *firmware;
+       const char firmware[FIRMWARE_NAME_MAX];
+       int (*download_firmware) (struct usb_device *, const struct firmware *);
+       int no_reconnect;
 
        int size_of_priv;
 
@@ -326,5 +333,15 @@ 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 *);
 
+/* commonly used firmware download types and function */
+struct hexline {
+       u8 len;
+       u32 addr;
+       u8 type;
+       u8 data[255];
+       u8 chk;
+};
+extern int dvb_usb_get_hexline(const struct firmware *, struct hexline *, int *);
+extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
 
 #endif
index fac48fc..412039d 100644 (file)
@@ -129,10 +129,6 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
                dibusb_read_eeprom_byte(d,i, &b);
 
                mac[5 - (i - 136)] = b;
-
-/*             deb_ee("%02x ",b);
-               if ((i+1) % 16 == 0)
-                       deb_ee("\n");*/
        }
 
        return 0;
@@ -153,7 +149,7 @@ static struct usb_device_id nova_t_table [] = {
 /* 01 */       { USB_DEVICE(USB_VID_HAUPPAUGE,     USB_PID_WINTV_NOVA_T_USB2_WARM) },
                        { }             /* Terminating entry */
 };
-MODULE_DEVICE_TABLE (usb, nova_t_table);
+MODULE_DEVICE_TABLE(usb, nova_t_table);
 
 static struct dvb_usb_properties nova_t_properties = {
        .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
@@ -198,6 +194,7 @@ static struct dvb_usb_properties nova_t_properties = {
                        { &nova_t_table[0], NULL },
                        { &nova_t_table[1], NULL },
                },
+               { NULL },
        }
 };
 
index 104b5d0..0885d9f 100644 (file)
@@ -190,7 +190,7 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
 }
 
 static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
-                                   struct dvb_diseqc_master_cmd *m)
+                                   struct dvb_diseqc_master_cmd *m)
 {
        struct vp702x_fe_state *st = fe->demodulator_priv;
        u8 cmd[8],ibuf[10];
index 4a3e8c7..a808d48 100644 (file)
@@ -13,47 +13,47 @@ extern int dvb_usb_vp702x_debug;
 /* commands are read and written with USB control messages */
 
 /* consecutive read/write operation */
-#define REQUEST_OUT       0xB2
-#define REQUEST_IN               0xB3
+#define REQUEST_OUT            0xB2
+#define REQUEST_IN             0xB3
 
 /* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0
  * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer
  * the returning buffer looks as follows
  * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */
 
-#define GET_TUNER_STATUS  0x05
+#define GET_TUNER_STATUS       0x05
 /* additional in buffer:
  * 0   1   2    3              4   5   6               7       8
  * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */
 
-#define GET_SYSTEM_STRING 0x06
+#define GET_SYSTEM_STRING      0x06
 /* additional in buffer:
  * 0   1   2   3   4   5   6   7   8
  * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */
 
-#define SET_DISEQC_CMD    0x08
+#define SET_DISEQC_CMD         0x08
 /* additional out buffer:
  * 0    1  2  3  4
  * len  X1 X2 X3 X4
  * additional in buffer:
  * 0   1 2
- * N/A 0 0   b[1] == b[2] == 0 -> success otherwise not */
+ * N/A 0 0   b[1] == b[2] == 0 -> success, failure otherwise */
 
-#define SET_LNB_POWER     0x09
+#define SET_LNB_POWER          0x09
 /* additional out buffer:
  * 0    1    2
  * 0x00 0xff 1 = on, 0 = off
  * additional in buffer:
  * 0   1 2
- * N/A 0 0   b[1] == b[2] == 0 -> success otherwise not */
+ * N/A 0 0   b[1] == b[2] == 0 -> success failure otherwise */
 
-#define GET_MAC_ADDRESS   0x0A
+#define GET_MAC_ADDRESS                0x0A
 /* #define GET_MAC_ADDRESS   0x0B */
 /* additional in buffer:
  * 0   1   2            3    4    5    6    7    8
  * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */
 
-#define SET_PID_FILTER    0x11
+#define SET_PID_FILTER         0x11
 /* additional in buffer:
  * 0        1        ... 14       15       16
  * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */
@@ -64,39 +64,38 @@ extern int dvb_usb_vp702x_debug;
  * freq0 freq1 divstep srate0 srate1 srate2 flag chksum
  */
 
-
 /* one direction requests */
-#define READ_REMOTE_REQ       0xB4
+#define READ_REMOTE_REQ                0xB4
 /* IN  i: 0; v: 0; b[0] == request, b[1] == key */
 
-#define READ_PID_NUMBER_REQ   0xB5
+#define READ_PID_NUMBER_REQ    0xB5
 /* IN  i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */
 
-#define WRITE_EEPROM_REQ      0xB6
+#define WRITE_EEPROM_REQ       0xB6
 /* OUT i: offset; v: value to write; no extra buffer */
 
-#define READ_EEPROM_REQ       0xB7
+#define READ_EEPROM_REQ                0xB7
 /* IN  i: bufferlen; v: offset; buffer with bufferlen bytes */
 
-#define READ_STATUS           0xB8
+#define READ_STATUS            0xB8
 /* IN  i: 0; v: 0; bufferlen 10 */
 
-#define READ_TUNER_REG_REQ    0xB9
+#define READ_TUNER_REG_REQ     0xB9
 /* IN  i: 0; v: register; b[0] = value */
 
-#define READ_FX2_REG_REQ      0xBA
+#define READ_FX2_REG_REQ       0xBA
 /* IN  i: offset; v: 0; b[0] = value */
 
-#define WRITE_FX2_REG_REQ     0xBB
+#define WRITE_FX2_REG_REQ      0xBB
 /* OUT i: offset; v: value to write; 1 byte extra buffer */
 
-#define SET_TUNER_POWER_REQ   0xBC
+#define SET_TUNER_POWER_REQ    0xBC
 /* IN  i: 0 = power off, 1 = power on */
 
-#define WRITE_TUNER_REG_REQ   0xBD
+#define WRITE_TUNER_REG_REQ    0xBD
 /* IN  i: register, v: value to write, no extra buffer */
 
-#define RESET_TUNER           0xBE
+#define RESET_TUNER            0xBE
 /* IN  i: 0, v: 0, no extra buffer */
 
 extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
index 3835235..0282049 100644 (file)
@@ -247,7 +247,7 @@ static struct dvb_usb_properties vp7045_properties = {
                  .cold_ids = { &vp7045_usb_table[2], NULL },
                  .warm_ids = { &vp7045_usb_table[3], NULL },
                },
-               { NULL },
+               { 0 },
        }
 };
 
index 8e269e1..db3a8b4 100644 (file)
@@ -16,6 +16,12 @@ config DVB_CX24110
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_CX24123
+       tristate "Conexant CX24123 based"
+       depends on DVB_CORE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
 config DVB_TDA8083
        tristate "Philips TDA8083 based"
        depends on DVB_CORE
@@ -50,18 +56,19 @@ comment "DVB-T (terrestrial) frontends"
        depends on DVB_CORE
 
 config DVB_SP8870
-       tristate "Spase sp8870 based"
+       tristate "Spase sp8870 based"
        depends on DVB_CORE
        select FW_LOADER
        help
-         A DVB-T tuner module. Say Y when you want to support this frontend.
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
          This driver needs external firmware. Please use the command
          "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
-         download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_SP887X
-       tristate "Spase sp887x based"
+       tristate "Spase sp887x based"
        depends on DVB_CORE
        select FW_LOADER
        help
@@ -69,7 +76,8 @@ config DVB_SP887X
 
          This driver needs external firmware. Please use the command
          "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
-         download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_CX22700
        tristate "Conexant CX22700 based"
@@ -78,10 +86,10 @@ config DVB_CX22700
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_CX22702
-       tristate "Conexant cx22702 demodulator (OFDM)"
-       depends on DVB_CORE
-       help
-         A DVB-T tuner module. Say Y when you want to support this frontend.
+       tristate "Conexant cx22702 demodulator (OFDM)"
+       depends on DVB_CORE
+       help
+         A DVB-T tuner module. Say Y when you want to support this frontend.
 
 config DVB_L64781
        tristate "LSI L64781"
@@ -98,8 +106,9 @@ config DVB_TDA1004X
 
          This driver needs external firmware. Please use the commands
          "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
-         download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+         download/extract them, and then copy them to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_NXT6000
        tristate "NxtWave Communications NXT6000 based"
@@ -140,13 +149,13 @@ config DVB_VES1820
        tristate "VLSI VES1820 based"
        depends on DVB_CORE
        help
-         A DVB-C tuner module. Say Y when you want to support this frontend.
+         A DVB-C tuner module. Say Y when you want to support this frontend.
 
 config DVB_TDA10021
        tristate "Philips TDA10021 based"
        depends on DVB_CORE
        help
-         A DVB-C tuner module. Say Y when you want to support this frontend.
+         A DVB-C tuner module. Say Y when you want to support this frontend.
 
 config DVB_STV0297
        tristate "ST STV0297 based"
@@ -164,6 +173,11 @@ config DVB_NXT2002
        help
          An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
 
+         This driver needs external firmware. Please use the command
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
+
 config DVB_NXT200X
        tristate "Nextwave NXT2002/NXT2004 based"
        depends on DVB_CORE
@@ -172,6 +186,12 @@ config DVB_NXT200X
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
+         This driver needs external firmware. Please use the commands
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+         download/extract them, and then copy them to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
+
 config DVB_OR51211
        tristate "or51211 based (pcHDTV HD2000 card)"
        depends on DVB_CORE
index a98760f..615ec83 100644 (file)
@@ -32,3 +32,4 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
 obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+obj-$(CONFIG_DVB_CX24123) += cx24123.o
index 8ceb9a3..3b132ba 100644 (file)
@@ -255,7 +255,7 @@ static int bcm3510_bert_reset(struct bcm3510_state *st)
        bcm3510_register_value b;
        int ret;
 
-       if ((ret < bcm3510_readB(st,0xfa,&b)) < 0)
+       if ((ret = bcm3510_readB(st,0xfa,&b)) < 0)
                return ret;
 
        b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
@@ -623,13 +623,13 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe)
                err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
                return ret;
        }
-       deb_info("got firmware: %d\n",fw->size);
+       deb_info("got firmware: %zd\n",fw->size);
 
        b = fw->data;
        for (i = 0; i < fw->size;) {
                addr = le16_to_cpu( *( (u16 *)&b[i] ) );
                len  = le16_to_cpu( *( (u16 *)&b[i+2] ) );
-               deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size);
+               deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
                if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
                        err("firmware download failed: %d\n",ret);
                        return ret;
index 5de0e6d..0fc899f 100644 (file)
@@ -195,6 +195,16 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet
        return 0;
 }
 
+static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct cx22702_state* state = fe->demodulator_priv;
+       dprintk ("%s(%d)\n", __FUNCTION__, enable);
+       if (enable)
+               return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe);
+       else
+               return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1);
+}
+
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
 static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
@@ -202,7 +212,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
        struct cx22702_state* state = fe->demodulator_priv;
 
        /* set PLL */
-       cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+       cx22702_i2c_gate_ctrl(fe, 1);
        if (state->config->pll_set) {
                state->config->pll_set(fe, p);
        } else if (state->config->pll_desc) {
@@ -216,7 +226,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
        } else {
                BUG();
        }
-       cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+       cx22702_i2c_gate_ctrl(fe, 0);
 
        /* set inversion */
        cx22702_set_inversion (state, p->inversion);
@@ -349,11 +359,10 @@ 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) {
-               cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe);
+       if (state->config->pll_init)
                state->config->pll_init(fe);
-               cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
-       }
+
+       cx22702_i2c_gate_ctrl(fe, 0);
 
        return 0;
 }
@@ -531,6 +540,7 @@ 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);
index 0c4db80..d15d32c 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/jiffies.h>
 
 #include "dvb_frontend.h"
 #include "cx24110.h"
@@ -56,7 +55,7 @@ static int debug;
 
 static struct {u8 reg; u8 data;} cx24110_regdata[]=
                      /* Comments beginning with @ denote this value should
-                        be the default */
+                        be the default */
        {{0x09,0x01}, /* SoftResetAll */
         {0x09,0x00}, /* release reset */
         {0x01,0xe8}, /* MSB of code rate 27.5MS/s */
@@ -67,26 +66,26 @@ static struct {u8 reg; u8 data;} cx24110_regdata[]=
         {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */
         {0x0a,0x00}, /* @ partial chip disables, do not set */
         {0x0b,0x01}, /* set output clock in gapped mode, start signal low
-                        active for first byte */
+                        active for first byte */
         {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */
         {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */
         {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1
-                        to avoid starting the BER counter. Reset the
-                        CRC test bit. Finite counting selected */
+                        to avoid starting the BER counter. Reset the
+                        CRC test bit. Finite counting selected */
         {0x15,0xff}, /* @ size of the limited time window for RS BER
-                        estimation. It is <value>*256 RS blocks, this
-                        gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
+                        estimation. It is <value>*256 RS blocks, this
+                        gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
         {0x16,0x00}, /* @ enable all RS output ports */
         {0x17,0x04}, /* @ time window allowed for the RS to sync */
         {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned
-                        for automatically */
+                        for automatically */
                      /* leave the current code rate and normalization
-                        registers as they are after reset... */
+                        registers as they are after reset... */
         {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
-                        only once */
+                        only once */
         {0x23,0x18}, /* @ size of the limited time window for Viterbi BER
-                        estimation. It is <value>*65536 channel bits, i.e.
-                        approx. 38ms at 27.5MS/s, rate 3/4 */
+                        estimation. It is <value>*65536 channel bits, i.e.
+                        approx. 38ms at 27.5MS/s, rate 3/4 */
         {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */
                      /* leave front-end AGC parameters at default values */
                      /* leave decimation AGC parameters at default values */
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
new file mode 100644 (file)
index 0000000..d661c6f
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+    Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+
+    Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+
+    Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24123.h"
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk (KERN_DEBUG "cx24123: " args); \
+       } while (0)
+
+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;
+       u32 VGAarg;
+       u32 bandselectarg;
+       u32 pllarg;
+
+       /* The Demod/Tuner can't easily provide these, we cache them */
+       u32 currentfreq;
+       u32 currentsymbolrate;
+};
+
+/* Various tuner defaults need to be established for a given symbol rate Sps */
+static struct
+{
+       u32 symbolrate_low;
+       u32 symbolrate_high;
+       u32 VCAslope;
+       u32 VCAoffset;
+       u32 VGA1offset;
+       u32 VGA2offset;
+       u32 VCAprogdata;
+       u32 VGAprogdata;
+} cx24123_AGC_vals[] =
+{
+       {
+               .symbolrate_low         = 1000000,
+               .symbolrate_high        = 4999999,
+               .VCAslope               = 0x07,
+               .VCAoffset              = 0x0f,
+               .VGA1offset             = 0x1f8,
+               .VGA2offset             = 0x1f8,
+               .VGAprogdata            = (2 << 18) | (0x1f8 << 9) | 0x1f8,
+               .VCAprogdata            = (4 << 18) | (0x07 << 9) | 0x07,
+       },
+       {
+               .symbolrate_low         =  5000000,
+               .symbolrate_high        = 14999999,
+               .VCAslope               = 0x1f,
+               .VCAoffset              = 0x1f,
+               .VGA1offset             = 0x1e0,
+               .VGA2offset             = 0x180,
+               .VGAprogdata            = (2 << 18) | (0x180 << 9) | 0x1e0,
+               .VCAprogdata            = (4 << 18) | (0x07 << 9) | 0x1f,
+       },
+       {
+               .symbolrate_low         = 15000000,
+               .symbolrate_high        = 45000000,
+               .VCAslope               = 0x3f,
+               .VCAoffset              = 0x3f,
+               .VGA1offset             = 0x180,
+               .VGA2offset             = 0x100,
+               .VGAprogdata            = (2 << 18) | (0x100 << 9) | 0x180,
+               .VCAprogdata            = (4 << 18) | (0x07 << 9) | 0x3f,
+       },
+};
+
+/*
+ * Various tuner defaults need to be established for a given frequency kHz.
+ * fixme: The bounds on the bands do not match the doc in real life.
+ * fixme: Some of them have been moved, other might need adjustment.
+ */
+static struct
+{
+       u32 freq_low;
+       u32 freq_high;
+       u32 bandselect;
+       u32 VCOdivider;
+       u32 VCOnumber;
+       u32 progdata;
+} cx24123_bandselect_vals[] =
+{
+       {
+               .freq_low       = 950000,
+               .freq_high      = 1018999,
+               .bandselect     = 0x40,
+               .VCOdivider     = 4,
+               .VCOnumber      = 7,
+               .progdata       = (0 << 18) | (0 << 9) | 0x40,
+       },
+       {
+               .freq_low       = 1019000,
+               .freq_high      = 1074999,
+               .bandselect     = 0x80,
+               .VCOdivider     = 4,
+               .VCOnumber      = 8,
+               .progdata       = (0 << 18) | (0 << 9) | 0x80,
+       },
+       {
+               .freq_low       = 1075000,
+               .freq_high      = 1227999,
+               .bandselect     = 0x01,
+               .VCOdivider     = 2,
+               .VCOnumber      = 1,
+               .progdata       = (0 << 18) | (1 << 9) | 0x01,
+       },
+       {
+               .freq_low       = 1228000,
+               .freq_high      = 1349999,
+               .bandselect     = 0x02,
+               .VCOdivider     = 2,
+               .VCOnumber      = 2,
+               .progdata       = (0 << 18) | (1 << 9) | 0x02,
+       },
+       {
+               .freq_low       = 1350000,
+               .freq_high      = 1481999,
+               .bandselect     = 0x04,
+               .VCOdivider     = 2,
+               .VCOnumber      = 3,
+               .progdata       = (0 << 18) | (1 << 9) | 0x04,
+       },
+       {
+               .freq_low       = 1482000,
+               .freq_high      = 1595999,
+               .bandselect     = 0x08,
+               .VCOdivider     = 2,
+               .VCOnumber      = 4,
+               .progdata       = (0 << 18) | (1 << 9) | 0x08,
+       },
+       {
+               .freq_low       = 1596000,
+               .freq_high      = 1717999,
+               .bandselect     = 0x10,
+               .VCOdivider     = 2,
+               .VCOnumber      = 5,
+               .progdata       = (0 << 18) | (1 << 9) | 0x10,
+       },
+       {
+               .freq_low       = 1718000,
+               .freq_high      = 1855999,
+               .bandselect     = 0x20,
+               .VCOdivider     = 2,
+               .VCOnumber      = 6,
+               .progdata       = (0 << 18) | (1 << 9) | 0x20,
+       },
+       {
+               .freq_low       = 1856000,
+               .freq_high      = 2035999,
+               .bandselect     = 0x40,
+               .VCOdivider     = 2,
+               .VCOnumber      = 7,
+               .progdata       = (0 << 18) | (1 << 9) | 0x40,
+       },
+       {
+               .freq_low       = 2036000,
+               .freq_high      = 2149999,
+               .bandselect     = 0x80,
+               .VCOdivider     = 2,
+               .VCOnumber      = 8,
+               .progdata       = (0 << 18) | (1 << 9) | 0x80,
+       },
+};
+
+static struct {
+       u8 reg;
+       u8 data;
+} cx24123_regdata[] =
+{
+       {0x00, 0x03}, /* Reset system */
+       {0x00, 0x00}, /* Clear reset */
+       {0x01, 0x3b}, /* Apply sensible defaults, from an i2c sniffer */
+       {0x03, 0x07},
+       {0x04, 0x10},
+       {0x05, 0x04},
+       {0x06, 0x31},
+       {0x0d, 0x02},
+       {0x0e, 0x03},
+       {0x0f, 0xfe},
+       {0x10, 0x01},
+       {0x14, 0x01},
+       {0x15, 0x98},
+       {0x16, 0x00},
+       {0x17, 0x01},
+       {0x1b, 0x05},
+       {0x1c, 0x80},
+       {0x1d, 0x00},
+       {0x1e, 0x00},
+       {0x20, 0x41},
+       {0x21, 0x15},
+       {0x27, 0x14},
+       {0x28, 0x46},
+       {0x29, 0x00},
+       {0x2a, 0xb0},
+       {0x2b, 0x73},
+       {0x2c, 0x00},
+       {0x2d, 0x00},
+       {0x2e, 0x00},
+       {0x2f, 0x00},
+       {0x30, 0x00},
+       {0x31, 0x00},
+       {0x32, 0x8c},
+       {0x33, 0x00},
+       {0x34, 0x00},
+       {0x35, 0x03},
+       {0x36, 0x02},
+       {0x37, 0x3a},
+       {0x3a, 0x00},   /* Enable AGC accumulator */
+       {0x44, 0x00},
+       {0x45, 0x00},
+       {0x46, 0x05},
+       {0x56, 0x41},
+       {0x57, 0xff},
+       {0x67, 0x83},
+};
+
+static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
+{
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+       int err;
+
+       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+               printk("%s: writereg error(err == %i, reg == 0x%02x,"
+                        " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+               return -EREMOTEIO;
+       }
+
+       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 ((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;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
+               { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+               { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2) {
+               printk("%s: reg=0x%x (error=%d)\n", __FUNCTION__, reg, ret);
+               return ret;
+       }
+
+       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)
+{
+       switch (inversion) {
+       case INVERSION_OFF:
+               cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f);
+               cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+               break;
+       case INVERSION_ON:
+               cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80);
+               cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80);
+               break;
+       case INVERSION_AUTO:
+               cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion)
+{
+       u8 val;
+
+       val = cx24123_readreg(state, 0x1b) >> 7;
+
+       if (val == 0)
+               *inversion = INVERSION_OFF;
+       else
+               *inversion = INVERSION_ON;
+
+       return 0;
+}
+
+static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
+{
+       if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
+               fec = FEC_AUTO;
+
+       /* Hardware has 5/11 and 3/5 but are never unused */
+       switch (fec) {
+       case FEC_NONE:
+               return cx24123_writereg(state, 0x0f, 0x01);
+       case FEC_1_2:
+               return cx24123_writereg(state, 0x0f, 0x02);
+       case FEC_2_3:
+               return cx24123_writereg(state, 0x0f, 0x04);
+       case FEC_3_4:
+               return cx24123_writereg(state, 0x0f, 0x08);
+       case FEC_5_6:
+               return cx24123_writereg(state, 0x0f, 0x20);
+       case FEC_7_8:
+               return cx24123_writereg(state, 0x0f, 0x80);
+       case FEC_AUTO:
+               return cx24123_writereg(state, 0x0f, 0xae);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec)
+{
+       int ret;
+       u8 val;
+
+       ret = cx24123_readreg (state, 0x1b);
+       if (ret < 0)
+               return ret;
+       val = ret & 0x07;
+       switch (val) {
+       case 1:
+               *fec = FEC_1_2;
+               break;
+       case 3:
+               *fec = FEC_2_3;
+               break;
+       case 4:
+               *fec = FEC_3_4;
+               break;
+       case 5:
+               *fec = FEC_4_5;
+               break;
+       case 6:
+               *fec = FEC_5_6;
+               break;
+       case 7:
+               *fec = FEC_7_8;
+               break;
+       case 2: /* *fec = FEC_3_5; break; */
+       case 0: /* *fec = FEC_5_11; break; */
+               *fec = FEC_AUTO;
+               break;
+       default:
+               *fec = FEC_NONE; // can't happen
+       }
+
+       return 0;
+}
+
+/* fixme: Symbol rates < 3MSps may not work because of precision loss */
+static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
+{
+       u32 val;
+
+       val = (srate / 1185) * 100;
+
+       /* Compensate for scaling up, by removing 17 symbols per 1Msps */
+       val = val - (17 * (srate / 1000000));
+
+       cx24123_writereg(state, 0x08, (val >> 16) & 0xff );
+       cx24123_writereg(state, 0x09, (val >>  8) & 0xff );
+       cx24123_writereg(state, 0x0a, (val      ) & 0xff );
+
+       return 0;
+}
+
+/*
+ * Based on the required frequency and symbolrate, the tuner AGC has to be configured
+ * and the correct band selected. Calculate those values
+ */
+static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       u32 ndiv = 0, adiv = 0, vco_div = 0;
+       int i = 0;
+
+       /* Defaults for low freq, low rate */
+       state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
+       state->VGAarg = cx24123_AGC_vals[0].VGAprogdata;
+       state->bandselectarg = cx24123_bandselect_vals[0].progdata;
+       vco_div = cx24123_bandselect_vals[0].VCOdivider;
+
+       /* For the given symbolerate, determine the VCA and VGA programming bits */
+       for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
+       {
+               if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
+                               (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
+                       state->VCAarg = cx24123_AGC_vals[i].VCAprogdata;
+                       state->VGAarg = cx24123_AGC_vals[i].VGAprogdata;
+               }
+       }
+
+       /* For the given frequency, determine the bandselect programming bits */
+       for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++)
+       {
+               if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) &&
+                               (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) {
+                       state->bandselectarg = cx24123_bandselect_vals[i].progdata;
+                       vco_div = cx24123_bandselect_vals[i].VCOdivider;
+               }
+       }
+
+       /* Determine the N/A dividers for the requested lband freq (in kHz). */
+       /* Note: 10111 (kHz) is the Crystal Freq and divider of 10. */
+       ndiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) / 32) & 0x1ff;
+       adiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) % 32) & 0x1f;
+
+       if (adiv == 0)
+               adiv++;
+
+       /* determine the correct pll frequency values. */
+       /* Command 11, refdiv 11, cpump polarity 1, cpump current 3mA 10. */
+       state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (2 << 14);
+       state->pllarg |= (ndiv << 5) | adiv;
+
+       return 0;
+}
+
+/*
+ * Tuner data is 21 bits long, must be left-aligned in data.
+ * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip.
+ */
+static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       unsigned long timeout;
+
+       /* align the 21 bytes into to bit23 boundary */
+       data = data << 3;
+
+       /* Reset the demod pll word length to 0x15 bits */
+       cx24123_writereg(state, 0x21, 0x15);
+
+       /* write the msb 8 bits, wait for the send to be completed */
+       timeout = jiffies + msecs_to_jiffies(40);
+       cx24123_writereg(state, 0x22, (data >> 16) & 0xff);
+       while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+               if (time_after(jiffies, timeout)) {
+                       printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+                       return -EREMOTEIO;
+               }
+               msleep(10);
+       }
+
+       /* send another 8 bytes, wait for the send to be completed */
+       timeout = jiffies + msecs_to_jiffies(40);
+       cx24123_writereg(state, 0x22, (data>>8) & 0xff );
+       while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
+               if (time_after(jiffies, timeout)) {
+                       printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+                       return -EREMOTEIO;
+               }
+               msleep(10);
+       }
+
+       /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */
+       timeout = jiffies + msecs_to_jiffies(40);
+       cx24123_writereg(state, 0x22, (data) & 0xff );
+       while ((cx24123_readreg(state, 0x20) & 0x80)) {
+               if (time_after(jiffies, timeout)) {
+                       printk("%s:  demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+                       return -EREMOTEIO;
+               }
+               msleep(10);
+       }
+
+       /* Trigger the demod to configure the tuner */
+       cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2);
+       cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd);
+
+       return 0;
+}
+
+static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       if (cx24123_pll_calculate(fe, p) != 0) {
+               printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__);
+               return -EINVAL;
+       }
+
+       /* Write the new VCO/VGA */
+       cx24123_pll_writereg(fe, p, state->VCAarg);
+       cx24123_pll_writereg(fe, p, state->VGAarg);
+
+       /* Write the new bandselect and pll args */
+       cx24123_pll_writereg(fe, p, state->bandselectarg);
+       cx24123_pll_writereg(fe, p, state->pllarg);
+
+       return 0;
+}
+
+static int cx24123_initfe(struct dvb_frontend* fe)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       int i;
+
+       /* Configure the demod to a good set of defaults */
+       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;
+}
+
+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_readlnbreg(state, 0x0);
+
+               switch (voltage) {
+               case SEC_VOLTAGE_13:
+                       return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
+               case SEC_VOLTAGE_18:
+                       return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
+               case SEC_VOLTAGE_OFF:
+                       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;
+               };
+       }
+
+       return 0;
+}
+
+static int cx24123_send_diseqc_msg(struct dvb_frontend* fe,
+                                  struct dvb_diseqc_master_cmd *cmd)
+{
+       /* fixme: Implement diseqc */
+       printk("%s: No support yet\n",__FUNCTION__);
+
+       return -ENOTSUPP;
+}
+
+static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       int sync = cx24123_readreg(state, 0x14);
+       int lock = cx24123_readreg(state, 0x20);
+
+       *status = 0;
+       if (lock & 0x01)
+               *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+       if (sync & 0x04)
+               *status |= FE_HAS_VITERBI;
+       if (sync & 0x08)
+               *status |= FE_HAS_CARRIER;
+       if (sync & 0x80)
+               *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+
+       return 0;
+}
+
+/*
+ * Configured to return the measurement of errors in blocks, because no UCBLOCKS value
+ * is available, so this value doubles up to satisfy both measurements
+ */
+static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       state->lastber =
+               ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
+               (cx24123_readreg(state, 0x1d) << 8 |
+               cx24123_readreg(state, 0x1e));
+
+       /* Do the signal quality processing here, it's derived from the BER. */
+       /* Scale the BER from a 24bit to a SNR 16 bit where higher = better */
+       if (state->lastber < 5000)
+               state->snr = 655*100;
+       else if ( (state->lastber >=   5000) && (state->lastber <  55000) )
+               state->snr = 655*90;
+       else if ( (state->lastber >=  55000) && (state->lastber < 150000) )
+               state->snr = 655*80;
+       else if ( (state->lastber >= 150000) && (state->lastber < 250000) )
+               state->snr = 655*70;
+       else if ( (state->lastber >= 250000) && (state->lastber < 450000) )
+               state->snr = 655*65;
+       else
+               state->snr = 0;
+
+       *ber = state->lastber;
+
+       return 0;
+}
+
+static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
+
+       return 0;
+}
+
+static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       *snr = state->snr;
+
+       return 0;
+}
+
+static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       *ucblocks = state->lastber;
+
+       return 0;
+}
+
+static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       if (state->config->set_ts_params)
+               state->config->set_ts_params(fe, 0);
+
+       state->currentfreq=p->frequency;
+       state->currentsymbolrate = p->u.qpsk.symbol_rate;
+
+       cx24123_set_inversion(state, p->inversion);
+       cx24123_set_fec(state, p->u.qpsk.fec_inner);
+       cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate);
+       cx24123_pll_tune(fe, p);
+
+       /* Enable automatic aquisition and reset cycle */
+       cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07));
+       cx24123_writereg(state, 0x00, 0x10);
+       cx24123_writereg(state, 0x00, 0);
+
+       return 0;
+}
+
+static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+
+       if (cx24123_get_inversion(state, &p->inversion) != 0) {
+               printk("%s: Failed to get inversion status\n",__FUNCTION__);
+               return -EREMOTEIO;
+       }
+       if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) {
+               printk("%s: Failed to get fec status\n",__FUNCTION__);
+               return -EREMOTEIO;
+       }
+       p->frequency = state->currentfreq;
+       p->u.qpsk.symbol_rate = state->currentsymbolrate;
+
+       return 0;
+}
+
+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:
+                       return cx24123_writelnbreg(state, 0x0, val | 0x10);
+               case SEC_TONE_OFF:
+                       return cx24123_writelnbreg(state, 0x0, val & 0x2f);
+               default:
+                       printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+                       return -EINVAL;
+               }
+
+       case 0:
+
+               val = cx24123_readreg(state, 0x29);
+
+               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;
+}
+
+static void cx24123_release(struct dvb_frontend* fe)
+{
+       struct cx24123_state* state = fe->demodulator_priv;
+       dprintk("%s\n",__FUNCTION__);
+       kfree(state);
+}
+
+static struct dvb_frontend_ops cx24123_ops;
+
+struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+                                   struct i2c_adapter* i2c)
+{
+       struct cx24123_state* state = NULL;
+       int ret;
+
+       dprintk("%s\n",__FUNCTION__);
+
+       /* allocate memory for the internal state */
+       state = kmalloc(sizeof(struct cx24123_state), GFP_KERNEL);
+       if (state == NULL) {
+               printk("Unable to kmalloc\n");
+               goto error;
+       }
+
+       /* 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;
+       state->pllarg = 0;
+       state->currentfreq = 0;
+       state->currentsymbolrate = 0;
+
+       /* check if the demod is there */
+       ret = cx24123_readreg(state, 0x00);
+       if ((ret != 0xd1) && (ret != 0xe1)) {
+               printk("Version != d1 or e1\n");
+               goto error;
+       }
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       kfree(state);
+
+       return NULL;
+}
+
+static struct dvb_frontend_ops cx24123_ops = {
+
+       .info = {
+               .name = "Conexant CX24123/CX24109",
+               .type = FE_QPSK,
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+               .frequency_stepsize = 1011, /* kHz for QPSK frontends */
+               .frequency_tolerance = 29500,
+               .symbol_rate_min = 1000000,
+               .symbol_rate_max = 45000000,
+               .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 | FE_CAN_RECOVER
+       },
+
+       .release = cx24123_release,
+
+       .init = cx24123_initfe,
+       .set_frontend = cx24123_set_frontend,
+       .get_frontend = cx24123_get_frontend,
+       .read_status = cx24123_read_status,
+       .read_ber = cx24123_read_ber,
+       .read_signal_strength = cx24123_read_signal_strength,
+       .read_snr = cx24123_read_snr,
+       .read_ucblocks = cx24123_read_ucblocks,
+       .diseqc_send_master_cmd = cx24123_send_diseqc_msg,
+       .set_tone = cx24123_set_tone,
+       .set_voltage = cx24123_set_voltage,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx24123_attach);
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
new file mode 100644 (file)
index 0000000..0c922b5
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+    Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+
+    Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef CX24123_H
+#define CX24123_H
+
+#include <linux/dvb/frontend.h>
+
+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,
+                                          struct i2c_adapter* i2c);
+
+#endif /* CX24123_H */
index f857b86..a3d57ce 100644 (file)
@@ -107,18 +107,19 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
 };
 EXPORT_SYMBOL(dvb_pll_microtune_4042);
 
-struct dvb_pll_desc dvb_pll_thomson_dtt7611 = {
-       .name  = "Thomson dtt7611",
-       .min   =  44000000,
-       .max   = 958000000,
+struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+       /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
+       .name  = "Thomson dtt761x",
+       .min   =  57000000,
+       .max   = 863000000,
        .count = 3,
        .entries = {
-               { 157250000, 44000000, 62500, 0x8e, 0x39 },
-               { 454000000, 44000000, 62500, 0x8e, 0x3a },
+               { 147000000, 44000000, 62500, 0x8e, 0x39 },
+               { 417000000, 44000000, 62500, 0x8e, 0x3a },
                { 999999999, 44000000, 62500, 0x8e, 0x3c },
        },
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7611);
+EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
 
 struct dvb_pll_desc dvb_pll_unknown_1 = {
        .name  = "unknown 1", /* used by dntv live dvb-t */
index 497d31d..24d4d2e 100644 (file)
@@ -25,7 +25,7 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
 extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
 extern struct dvb_pll_desc dvb_pll_lg_z201;
 extern struct dvb_pll_desc dvb_pll_microtune_4042;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7611;
+extern struct dvb_pll_desc dvb_pll_thomson_dtt761x;
 extern struct dvb_pll_desc dvb_pll_unknown_1;
 
 extern struct dvb_pll_desc dvb_pll_tua6010xs;
index cb53018..9d21464 100644 (file)
@@ -27,6 +27,7 @@
  *   DViCO FusionHDTV 3 Gold-T
  *   DViCO FusionHDTV 5 Gold
  *   DViCO FusionHDTV 5 Lite
+ *   DViCO FusionHDTV 5 USB Gold
  *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
  *
  * TODO:
@@ -402,6 +403,8 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
                state->config->pll_set(fe, param);
 
        /* Keep track of the new frequency */
+       /* FIXME this is the wrong way to do this...           */
+       /* The tuner is shared with the video4linux analog API */
        state->current_frequency = param->frequency;
 
        lgdt330x_SwReset(state);
index 52c4160..4f263e6 100644 (file)
@@ -22,7 +22,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
 #define CRC_CCIT_MASK 0x1021
index a458a3b..a16eeba 100644 (file)
@@ -574,11 +574,11 @@ static struct dvb_frontend_ops nxt6000_ops = {
                .symbol_rate_max = 9360000,     /* FIXME */
                .symbol_rate_tolerance = 4000,
                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
-                       FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
-                       FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-                       FE_CAN_HIERARCHY_AUTO,
+                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+                       FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO,
        },
 
        .release = nxt6000_release,
index 531f762..7c3aed1 100644 (file)
@@ -25,7 +25,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw"
 
@@ -112,7 +113,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
        u8 tudata[585];
        int i;
 
-       dprintk("Firmware is %d bytes\n",fw->size);
+       dprintk("Firmware is %zd bytes\n",fw->size);
 
        /* Get eprom data */
        tudata[0] = 17;
index 1871509..d694775 100644 (file)
@@ -521,8 +521,8 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state,
 
                case FEC_3_4:
                        s5h1420_writereg(state, 0x30, 0x04);
-                       s5h1420_writereg(state, 0x31, 0x12 | inversion);
-                       break;
+                       s5h1420_writereg(state, 0x31, 0x12 | inversion);
+                       break;
 
                case FEC_5_6:
                        s5h1420_writereg(state, 0x30, 0x08);
index fc06cd6..73829e6 100644 (file)
@@ -22,7 +22,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
 
index e3b6657..eb8a602 100644 (file)
@@ -5,7 +5,8 @@
 /*
  * This driver needs external firmware. Please use the command
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw"
 
@@ -581,7 +582,7 @@ static struct dvb_frontend_ops sp887x_ops = {
                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
                        FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
                        FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-                       FE_CAN_RECOVER
+                       FE_CAN_RECOVER
        },
 
        .release = sp887x_release,
index 177d71d..5bcd00f 100644 (file)
@@ -131,6 +131,13 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len
        return ret == 2 ? 0 : ret;
 }
 
+int stv0299_enable_plli2c (struct dvb_frontend* fe)
+{
+       struct stv0299_state* state = fe->demodulator_priv;
+
+       return stv0299_writeregI(state, 0x05, 0xb5);    /*  enable i2c repeater on stv0299  */
+}
+
 static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
 {
        dprintk ("%s\n", __FUNCTION__);
@@ -387,7 +394,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag
        };
 }
 
-static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
+static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd)
 {
        struct stv0299_state* state = fe->demodulator_priv;
        u8 reg0x08;
@@ -407,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
 
        cmd = cmd << 1;
        if (debug_legacy_dish_switch)
-               printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
+               printk ("%s switch command: 0x%04lx\n",__FUNCTION__, cmd);
 
        do_gettimeofday (&nexttime);
        if (debug_legacy_dish_switch)
@@ -717,5 +724,6 @@ MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
              "Andreas Oberritter, Andrew de Quincey, Kenneth Aafl√ły");
 MODULE_LICENSE("GPL");
 
+EXPORT_SYMBOL(stv0299_enable_plli2c);
 EXPORT_SYMBOL(stv0299_writereg);
 EXPORT_SYMBOL(stv0299_attach);
index 9af3d71..32c87b4 100644 (file)
@@ -94,6 +94,7 @@ struct stv0299_config
 };
 
 extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
+extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
 
 extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
                                           struct i2c_adapter* i2c);
index 425cd19..21255ca 100644 (file)
@@ -95,7 +95,7 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
        u8 b0 [] = { reg };
        u8 b1 [] = { 0 };
        struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
-                                 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+                                 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
        int ret;
 
        ret = i2c_transfer (state->i2c, msg, 2);
@@ -434,7 +434,7 @@ static struct dvb_frontend_ops tda10021_ops = {
                .frequency_max = 858000000,
                .symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
                .symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
-       #if 0
+#if 0
                .frequency_tolerance = ???,
                .symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
        #endif
index dd02aff..c63e9a5 100644 (file)
@@ -23,7 +23,8 @@
  * This driver needs external firmware. Please use the commands
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
  * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
- * download/extract them, and then copy them to /usr/lib/hotplug/firmware.
+ * download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ * or /lib/firmware (depending on configuration of firmware hotplug).
  */
 #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw"
 #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
@@ -271,32 +272,57 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state,
 static int tda10046h_set_bandwidth(struct tda1004x_state *state,
                                   fe_bandwidth_t bandwidth)
 {
-       static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e };
-       static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 };
-       static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd };
-
+       static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
+       static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
+       static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
+
+       static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
+       static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
+       static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
+       int tda10046_clk53m;
+
+       if ((state->config->if_freq == TDA10046_FREQ_045) ||
+           (state->config->if_freq == TDA10046_FREQ_052))
+               tda10046_clk53m = 0;
+       else
+               tda10046_clk53m = 1;
        switch (bandwidth) {
        case BANDWIDTH_6_MHZ:
-               tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+               if (tda10046_clk53m)
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
+                                                 sizeof(bandwidth_6mhz_53M));
+               else
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M,
+                                                 sizeof(bandwidth_6mhz_48M));
                if (state->config->if_freq == TDA10046_FREQ_045) {
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09);
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab);
                }
                break;
 
        case BANDWIDTH_7_MHZ:
-               tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+               if (tda10046_clk53m)
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
+                                                 sizeof(bandwidth_7mhz_53M));
+               else
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M,
+                                                 sizeof(bandwidth_7mhz_48M));
                if (state->config->if_freq == TDA10046_FREQ_045) {
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
                }
                break;
 
        case BANDWIDTH_8_MHZ:
-               tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+               if (tda10046_clk53m)
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
+                                                 sizeof(bandwidth_8mhz_53M));
+               else
+                       tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M,
+                                                 sizeof(bandwidth_8mhz_48M));
                if (state->config->if_freq == TDA10046_FREQ_045) {
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
-                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+                       tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55);
                }
                break;
 
@@ -418,9 +444,22 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
 static void tda10046_init_plls(struct dvb_frontend* fe)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
+       int tda10046_clk53m;
+
+       if ((state->config->if_freq == TDA10046_FREQ_045) ||
+           (state->config->if_freq == TDA10046_FREQ_052))
+               tda10046_clk53m = 0;
+       else
+               tda10046_clk53m = 1;
 
        tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
-       tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10
+       if(tda10046_clk53m) {
+               printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
+               tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
+       } else {
+               printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
+               tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
+       }
        if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
                dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
                tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
@@ -428,26 +467,32 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
                dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__);
                tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
        }
-       tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
+       if(tda10046_clk53m)
+               tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67);
+       else
+               tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72);
+       /* Note clock frequency is handled implicitly */
        switch (state->config->if_freq) {
-       case TDA10046_FREQ_3617:
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
-               break;
-       case TDA10046_FREQ_3613:
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13);
-               break;
        case TDA10046_FREQ_045:
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00);
                break;
        case TDA10046_FREQ_052:
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
-               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7);
+               break;
+       case TDA10046_FREQ_3617:
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59);
+               break;
+       case TDA10046_FREQ_3613:
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7);
+               tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
                break;
        }
        tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
+       /* let the PLLs settle */
+       msleep(120);
 }
 
 static int tda10046_fwupload(struct dvb_frontend* fe)
@@ -462,13 +507,13 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
        /* let the clocks recover from sleep */
        msleep(5);
 
+       /* The PLLs need to be reprogrammed after sleep */
+       tda10046_init_plls(fe);
+
        /* don't re-upload unless necessary */
        if (tda1004x_check_upload_ok(state) == 0)
                return 0;
 
-       /* set parameters */
-       tda10046_init_plls(fe);
-
        if (state->config->request_firmware != NULL) {
                /* request the firmware, this will block until someone uploads it */
                printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
@@ -484,7 +529,6 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
                        return ret;
        } else {
                /* boot from firmware eeprom */
-               /* Hac Note: we might need to do some GPIO Magic here */
                printk(KERN_INFO "tda1004x: booting from eeprom\n");
                tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
                msleep(300);
@@ -606,10 +650,9 @@ static int tda10046_init(struct dvb_frontend* fe)
 
        // tda setup
        tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
-       tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream
-       tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer
+       tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
+       tda1004x_write_byteI(state, TDA1004X_CONFC1, 8);      // disable pulse killer
 
-       tda10046_init_plls(fe);
        switch (state->config->agc_config) {
        case TDA10046_AGC_DEFAULT:
                tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
@@ -626,25 +669,22 @@ static int tda10046_init(struct dvb_frontend* fe)
        case TDA10046_AGC_TDA827X:
                tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
                tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
-               tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize
-               tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+               tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+               tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
                break;
        }
+       tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
        tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
        tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);    // }
        tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
        tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);     // }
        tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff);  // }
-       tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
+       tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1
        tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
        tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
        tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
        tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
 
-       tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
-       tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
-       tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select
-
        state->initialised = 1;
        return 0;
 }
@@ -686,9 +726,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 
        // Set standard params.. or put them to auto
        if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
-           (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
-           (fe_params->u.ofdm.constellation == QAM_AUTO) ||
-           (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
+               (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
+               (fe_params->u.ofdm.constellation == QAM_AUTO) ||
+               (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
                tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1);        // enable auto
                tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits
                tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
@@ -851,6 +891,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
 {
        struct tda1004x_state* state = fe->demodulator_priv;
+
        dprintk("%s\n", __FUNCTION__);
 
        // inversion status
@@ -875,16 +916,18 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
                        break;
                }
                break;
-
        case TDA1004X_DEMOD_TDA10046:
                switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
-               case 0x60:
+               case 0x5c:
+               case 0x54:
                        fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
                        break;
-               case 0x6e:
+               case 0x6a:
+               case 0x60:
                        fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
                        break;
-               case 0x80:
+               case 0x7b:
+               case 0x70:
                        fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
                        break;
                }
index f02842b..84f8f9f 100644 (file)
@@ -8,7 +8,7 @@ config DVB_PLUTO2
          Support for PCI cards based on the Pluto2 FPGA like the Satelco
          Easywatch Mobile Terrestrial DVB-T Receiver.
 
-          Since these cards have no MPEG decoder onboard, they transmit
+         Since these cards have no MPEG decoder onboard, they transmit
          only compressed MPEG data over the PCI bus, so you need
          an external software decoder to watch TV on your computer.
 
index fa5034a..5b2aadb 100644 (file)
@@ -18,9 +18,10 @@ config DVB_AV7110
          This driver only supports the fullfeatured cards with
          onboard MPEG2 decoder.
 
-          This driver needs an external firmware. Please use the script
-          "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
-          download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+         This driver needs an external firmware. Please use the script
+         "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
+         download/extract it, and then copy it to /usr/lib/hotplug/firmware
+         or /lib/firmware (depending on configuration of firmware hotplug).
 
          Say Y if you own such a card and want to use it.
 
index 825ab1c..a690730 100644 (file)
@@ -16,7 +16,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 hostprogs-y    := fdump
 
 ifdef CONFIG_DVB_AV7110_FIRMWARE
-$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h 
+$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
 
 $(obj)/av7110_firm.h:
        $(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@
index 7dae91e..8ce4146 100644 (file)
@@ -133,7 +133,13 @@ static void init_av7110_av(struct av7110 *av7110)
        /* remaining inits according to card and frontend type */
        av7110->analog_tuner_flags = 0;
        av7110->current_input = 0;
-       if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
+       if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) {
+               printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n",
+                       av7110->dvb_adapter.num);
+               av7110->adac_type = DVB_ADAC_MSP34x5;
+               av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
+       }
+       else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
                printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
                        av7110->dvb_adapter.num);
                av7110->adac_type = DVB_ADAC_CRYSTAL;
@@ -156,10 +162,10 @@ static void init_av7110_av(struct av7110 *av7110)
        else {
                av7110->adac_type = adac;
                printk("dvb-ttpci: adac type set to %d @ card %d\n",
-                       av7110->dvb_adapter.num, av7110->adac_type);
+                       av7110->adac_type, av7110->dvb_adapter.num);
        }
 
-       if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
+       if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) {
                // switch DVB SCART on
                ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
                if (ret < 0)
@@ -190,17 +196,15 @@ static void recover_arm(struct av7110 *av7110)
 
        av7110_bootarm(av7110);
        msleep(100);
-       restart_feeds(av7110);
-       av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
-}
 
-static void arm_error(struct av7110 *av7110)
-{
-       dprintk(4, "%p\n",av7110);
+       init_av7110_av(av7110);
+
+       /* card-specific recovery */
+       if (av7110->recover)
+               av7110->recover(av7110);
 
-       av7110->arm_errors++;
-       av7110->arm_ready = 0;
-       recover_arm(av7110);
+       restart_feeds(av7110);
+       av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
 }
 
 static void av7110_arm_sync(struct av7110 *av7110)
@@ -240,26 +244,22 @@ static int arm_thread(void *data)
 
                if (down_interruptible(&av7110->dcomlock))
                        break;
-
                newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
                up(&av7110->dcomlock);
 
-               if (newloops == av7110->arm_loops) {
+               if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
                        printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
                               av7110->dvb_adapter.num);
 
-                       arm_error(av7110);
-                       av7710_set_video_mode(av7110, vidmode);
-
-                       init_av7110_av(av7110);
+                       recover_arm(av7110);
 
                        if (down_interruptible(&av7110->dcomlock))
                                break;
-
                        newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
                        up(&av7110->dcomlock);
                }
                av7110->arm_loops = newloops;
+               av7110->arm_errors = 0;
        }
 
        av7110->arm_thread = NULL;
@@ -510,10 +510,6 @@ static void gpioirq(unsigned long data)
                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
 
                av7110->video_size.h = h_ar & 0xfff;
-               dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
-                       av7110->video_size.w,
-                       av7110->video_size.h,
-                       av7110->video_size.aspect_ratio);
 
                event.type = VIDEO_EVENT_SIZE_CHANGED;
                event.u.size.w = av7110->video_size.w;
@@ -535,6 +531,11 @@ static void gpioirq(unsigned long data)
                        event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;
                        av7110->videostate.video_format = VIDEO_FORMAT_4_3;
                }
+
+               dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
+                       av7110->video_size.w, av7110->video_size.h,
+                       av7110->video_size.aspect_ratio);
+
                dvb_video_add_event(av7110, &event);
                break;
        }
@@ -714,6 +715,8 @@ static struct dvb_device dvbdev_osd = {
 static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
                          u16 subpid, u16 pcrpid)
 {
+       u16 aflags = 0;
+
        dprintk(4, "%p\n", av7110);
 
        if (vpid == 0x1fff || apid == 0x1fff ||
@@ -725,8 +728,11 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
                av7110->pids[DMX_PES_PCR] = 0;
        }
 
-       return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 5,
-                            pcrpid, vpid, apid, ttpid, subpid);
+       if (av7110->audiostate.bypass_mode)
+               aflags |= 0x8000;
+
+       return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6,
+                            pcrpid, vpid, apid, ttpid, subpid, aflags);
 }
 
 int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
@@ -1043,7 +1049,7 @@ static void restart_feeds(struct av7110 *av7110)
        struct dvb_demux *dvbdmx = &av7110->demux;
        struct dvb_demux_feed *feed;
        int mode;
-       int i;
+       int i, j;
 
        dprintk(4, "%p\n", av7110);
 
@@ -1051,10 +1057,21 @@ static void restart_feeds(struct av7110 *av7110)
        av7110->playing = 0;
        av7110->rec_mode = 0;
 
-       for (i = 0; i < dvbdmx->filternum; i++) {
+       for (i = 0; i < dvbdmx->feednum; i++) {
                feed = &dvbdmx->feed[i];
-               if (feed->state == DMX_STATE_GO)
+               if (feed->state == DMX_STATE_GO) {
+                       if (feed->type == DMX_TYPE_SEC) {
+                               for (j = 0; j < dvbdmx->filternum; j++) {
+                                       if (dvbdmx->filter[j].type != DMX_TYPE_SEC)
+                                               continue;
+                                       if (dvbdmx->filter[j].filter.parent != &feed->feed.sec)
+                                               continue;
+                                       if (dvbdmx->filter[j].state == DMX_STATE_GO)
+                                               dvbdmx->filter[j].state = DMX_STATE_READY;
+                               }
+                       }
                        av7110_start_feed(feed);
+               }
        }
 
        if (mode)
@@ -1483,9 +1500,9 @@ static int get_firmware(struct av7110* av7110)
                if (ret == -ENOENT) {
                        printk(KERN_ERR "dvb-ttpci: could not load firmware,"
                               " file not found: dvb-ttpci-01.fw\n");
-                       printk(KERN_ERR "dvb-ttpci: usually this should be in"
-                              " /usr/lib/hotplug/firmware\n");
-                       printk(KERN_ERR "dvb-ttpci: and can be downloaded here"
+                       printk(KERN_ERR "dvb-ttpci: usually this should be in "
+                              "/usr/lib/hotplug/firmware or /lib/firmware\n");
+                       printk(KERN_ERR "dvb-ttpci: and can be downloaded from"
                               " http://www.linuxtv.org/download/dvb/firmware/\n");
                } else
                        printk(KERN_ERR "dvb-ttpci: cannot request firmware"
@@ -2110,8 +2127,10 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_fe_params = *params;
                ret = av7110->fe_set_frontend(fe, params);
+       }
        return ret;
 }
 
@@ -2153,8 +2172,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_master_cmd = *cmd;
                ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
+       }
        return ret;
 }
 
@@ -2163,8 +2184,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_minicmd = minicmd;
                ret = av7110->fe_diseqc_send_burst(fe, minicmd);
+       }
        return ret;
 }
 
@@ -2173,8 +2196,10 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_tone = tone;
                ret = av7110->fe_set_tone(fe, tone);
+       }
        return ret;
 }
 
@@ -2183,12 +2208,14 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret)
+       if (!ret) {
+               av7110->saved_voltage = voltage;
                ret = av7110->fe_set_voltage(fe, voltage);
+       }
        return ret;
 }
 
-static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
+static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd)
 {
        struct av7110* av7110 = fe->dvb->priv;
 
@@ -2198,6 +2225,23 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un
        return ret;
 }
 
+static void dvb_s_recover(struct av7110* av7110)
+{
+       av7110_fe_init(av7110->fe);
+
+       av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage);
+       if (av7110->saved_master_cmd.msg_len) {
+               msleep(20);
+               av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd);
+       }
+       msleep(20);
+       av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd);
+       msleep(20);
+       av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
+
+       av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);
+}
+
 static u8 read_pwm(struct av7110* av7110)
 {
        u8 b = 0xff;
@@ -2235,6 +2279,7 @@ static int frontend_init(struct av7110 *av7110)
                                av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
                                av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
                                av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->recover = dvb_s_recover;
                                break;
                        }
 
@@ -2244,15 +2289,17 @@ static int frontend_init(struct av7110 *av7110)
                                av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
                                av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
                                av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->recover = dvb_s_recover;
                                break;
                        }
 
                        // Try the grundig 29504-451
-                       av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+                       av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
                        if (av7110->fe) {
                                av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
                                av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
                                av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->recover = dvb_s_recover;
                                break;
                        }
 
@@ -2274,12 +2321,12 @@ static int frontend_init(struct av7110 *av7110)
                case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
 
                        // ALPS TDLB7
-                       av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+                       av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
                        break;
 
                case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
 
-                       av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+                       av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
                        break;
 
                case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
@@ -2289,6 +2336,7 @@ static int frontend_init(struct av7110 *av7110)
                                av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
                                av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
                                av7110->fe->ops->set_tone = av7110_set_tone;
+                               av7110->recover = dvb_s_recover;
                        }
                        break;
 
@@ -2314,8 +2362,11 @@ static int frontend_init(struct av7110 *av7110)
                case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
                        /* ALPS BSBE1 */
                        av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
-                       if (av7110->fe)
+                       if (av7110->fe) {
                                av7110->fe->ops->set_voltage = lnbp21_set_voltage;
+                               av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+                               av7110->recover = dvb_s_recover;
+                       }
                        break;
                }
        }
index cce00ef..6ea30df 100644 (file)
@@ -98,7 +98,8 @@ struct av7110 {
        int adac_type;         /* audio DAC type */
 #define DVB_ADAC_TI      0
 #define DVB_ADAC_CRYSTAL  1
-#define DVB_ADAC_MSP     2
+#define DVB_ADAC_MSP34x0  2
+#define DVB_ADAC_MSP34x5  3
 #define DVB_ADAC_NONE   -1
 
 
@@ -228,6 +229,9 @@ struct av7110 {
        struct dvb_video_events  video_events;
        video_size_t             video_size;
 
+       u16                     wssMode;
+       u16                     wssData;
+
        u32                     ir_config;
        u32                     ir_command;
        void                    (*ir_handler)(struct av7110 *av7110, u32 ircom);
@@ -245,6 +249,15 @@ struct av7110 {
 
        struct dvb_frontend* fe;
        fe_status_t fe_status;
+
+       /* crash recovery */
+       void                            (*recover)(struct av7110* av7110);
+       struct dvb_frontend_parameters  saved_fe_params;
+       fe_sec_voltage_t                saved_voltage;
+       fe_sec_tone_mode_t              saved_tone;
+       struct dvb_diseqc_master_cmd    saved_master_cmd;
+       fe_sec_mini_cmd_t               saved_minicmd;
+
        int (*fe_init)(struct dvb_frontend* fe);
        int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
        int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
@@ -252,7 +265,7 @@ struct av7110 {
        int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
        int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
        int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
-       int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+       int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
        int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
index 0696a5a..400face 100644 (file)
@@ -309,7 +309,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
                i2c_writereg(av7110, 0x20, 0x04, volright);
                return 0;
 
-       case DVB_ADAC_MSP:
+       case DVB_ADAC_MSP34x0:
                vol  = (volleft > volright) ? volleft : volright;
                val     = (vol * 0x73 / 255) << 8;
                if (vol > 0)
@@ -1256,7 +1256,9 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                break;
 
        case AUDIO_SET_BYPASS_MODE:
-               ret = -EINVAL;
+               if (FW_VERSION(av7110->arm_app) < 0x2621)
+                       ret = -EINVAL;
+               av7110->audiostate.bypass_mode = (int)arg;
                break;
 
        case AUDIO_CHANNEL_SELECT:
@@ -1295,7 +1297,11 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                break;
 
        case AUDIO_GET_CAPABILITIES:
-               *(int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+               if (FW_VERSION(av7110->arm_app) < 0x2621)
+                       *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
+               else
+                       *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 |
+                                               AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
                break;
 
        case AUDIO_CLEAR_BUFFER:
index 87106e8..cb37745 100644 (file)
@@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110)
 
        dprintk(4, "%p\n", av7110);
 
+       av7110->arm_ready = 0;
+
        saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 
        /* Disable DEBI and GPIO irq */
@@ -361,6 +363,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
                        break;
                if (err) {
                        printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
+                       av7110->arm_errors++;
                        return -ETIMEDOUT;
                }
                msleep(1);
@@ -1206,9 +1209,9 @@ int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
        switch (cap->cmd) {
        case OSD_CAP_MEMSIZE:
                if (FW_4M_SDRAM(av7110->arm_app))
-                       cap->val = 1000000;
+                       cap->val = 1000000;
                else
-                       cap->val = 92000;
+                       cap->val = 92000;
                return 0;
        default:
                return -EINVAL;
index 2a5e87b..84b8329 100644 (file)
@@ -167,7 +167,8 @@ enum av7110_encoder_command {
        LoadVidCode,
        SetMonitorType,
        SetPanScanType,
-       SetFreezeMode
+       SetFreezeMode,
+       SetWSSConfig
 };
 
 enum av7110_rec_play_state {
index f5e59fc..9138132 100644 (file)
@@ -17,6 +17,8 @@ static int av_cnt;
 static struct av7110 *av_list[4];
 static struct input_dev *input_dev;
 
+static u8 delay_timer_finished;
+
 static u16 key_map [256] = {
        KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
        KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
@@ -112,13 +114,16 @@ static void av7110_emit_key(unsigned long parm)
        if (timer_pending(&keyup_timer)) {
                del_timer(&keyup_timer);
                if (keyup_timer.data != keycode || new_toggle != old_toggle) {
+                       delay_timer_finished = 0;
                        input_event(input_dev, EV_KEY, keyup_timer.data, !!0);
                        input_event(input_dev, EV_KEY, keycode, !0);
                } else
-                       input_event(input_dev, EV_KEY, keycode, 2);
-
-       } else
+                       if (delay_timer_finished)
+                               input_event(input_dev, EV_KEY, keycode, 2);
+       } else {
+               delay_timer_finished = 0;
                input_event(input_dev, EV_KEY, keycode, !0);
+       }
 
        keyup_timer.expires = jiffies + UP_TIMEOUT;
        keyup_timer.data = keycode;
@@ -145,7 +150,8 @@ static void input_register_keys(void)
 
 static void input_repeat_key(unsigned long data)
 {
-       /* dummy routine to disable autorepeat in the input driver */
+       /* called by the input driver after rep[REP_DELAY] ms */
+       delay_timer_finished = 1;
 }
 
 
index b5aea41..94cf38c 100644 (file)
@@ -490,6 +490,58 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
                break;
        }
+       case VIDIOC_G_SLICED_VBI_CAP:
+       {
+               struct v4l2_sliced_vbi_cap *cap = arg;
+               dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
+               memset(cap, 0, sizeof *cap);
+               if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+                       cap->service_set = V4L2_SLICED_WSS_625;
+                       cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+               }
+               break;
+       }
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *f = arg;
+               dprintk(2, "VIDIOC_G_FMT:\n");
+               if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+                   FW_VERSION(av7110->arm_app) < 0x2623)
+                       return -EAGAIN; /* handled by core driver */
+               memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+               if (av7110->wssMode) {
+                       f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+               }
+               break;
+       }
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *f = arg;
+               dprintk(2, "VIDIOC_S_FMT\n");
+               if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
+                   FW_VERSION(av7110->arm_app) < 0x2623)
+                       return -EAGAIN; /* handled by core driver */
+               if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
+                   f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
+                       memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+                       /* WSS controlled by firmware */
+                       av7110->wssMode = 0;
+                       av7110->wssData = 0;
+                       return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
+                                            SetWSSConfig, 1, 0);
+               } else {
+                       memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+                       f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+                       f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
+                       /* WSS controlled by userspace */
+                       av7110->wssMode = 1;
+                       av7110->wssData = 0;
+               }
+               break;
+       }
        default:
                printk("no such ioctl\n");
                return -ENOIOCTLCMD;
@@ -497,6 +549,46 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        return 0;
 }
 
+static int av7110_vbi_reset(struct inode *inode, struct file *file)
+{
+       struct saa7146_fh *fh = file->private_data;
+       struct saa7146_dev *dev = fh->dev;
+       struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+
+       dprintk(2, "%s\n", __FUNCTION__);
+       av7110->wssMode = 0;
+       av7110->wssData = 0;
+       if (FW_VERSION(av7110->arm_app) < 0x2623)
+               return 0;
+       else
+               return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+}
+
+static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
+{
+       struct saa7146_fh *fh = file->private_data;
+       struct saa7146_dev *dev = fh->dev;
+       struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+       struct v4l2_sliced_vbi_data d;
+       int rc;
+
+       dprintk(2, "%s\n", __FUNCTION__);
+       if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
+               return -EINVAL;
+       if (copy_from_user(&d, data, count))
+               return -EFAULT;
+       if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
+               return -EINVAL;
+       if (d.id) {
+               av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
+               rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
+                                  2, 1, av7110->wssData);
+       } else {
+               av7110->wssData = 0;
+               rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
+       }
+       return (rc < 0) ? rc : count;
+}
 
 /****************************************************************************
  * INITIALIZATION
@@ -512,6 +604,9 @@ static struct saa7146_extension_ioctls ioctls[] = {
        { VIDIOC_S_TUNER,       SAA7146_EXCLUSIVE },
        { VIDIOC_G_AUDIO,       SAA7146_EXCLUSIVE },
        { VIDIOC_S_AUDIO,       SAA7146_EXCLUSIVE },
+       { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
+       { VIDIOC_G_FMT,         SAA7146_BEFORE },
+       { VIDIOC_S_FMT,         SAA7146_BEFORE },
        { 0, 0 }
 };
 
@@ -587,7 +682,7 @@ int av7110_init_analog_module(struct av7110 *av7110)
 
        printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
                av7110->dvb_adapter.num);
-       av7110->adac_type = DVB_ADAC_MSP;
+       av7110->adac_type = DVB_ADAC_MSP34x0;
        msleep(100); // the probing above resets the msp...
        msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
        msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
@@ -692,12 +787,11 @@ int av7110_init_v4l(struct av7110 *av7110)
                saa7146_vv_release(dev);
                return -ENODEV;
        }
-       if (av7110->analog_tuner_flags) {
-               if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
-                       ERR(("cannot register vbi v4l2 device. skipping.\n"));
-               } else {
+       if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
+               ERR(("cannot register vbi v4l2 device. skipping.\n"));
+       } else {
+               if (av7110->analog_tuner_flags)
                        av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
-               }
        }
        return 0;
 }
@@ -778,7 +872,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
 static struct saa7146_ext_vv av7110_vv_data_st = {
        .inputs         = 1,
        .audios         = 1,
-       .capabilities   = 0,
+       .capabilities   = V4L2_CAP_SLICED_VBI_OUTPUT,
        .flags          = 0,
 
        .stds           = &standard[0],
@@ -787,12 +881,16 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
 
        .ioctls         = &ioctls[0],
        .ioctl          = av7110_ioctl,
+
+       .vbi_fops.open  = av7110_vbi_reset,
+       .vbi_fops.release = av7110_vbi_reset,
+       .vbi_fops.write = av7110_vbi_write,
 };
 
 static struct saa7146_ext_vv av7110_vv_data_c = {
        .inputs         = 1,
        .audios         = 1,
-       .capabilities   = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
+       .capabilities   = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
        .flags          = SAA7146_USE_PORT_B_FOR_VBI,
 
        .stds           = &standard[0],
@@ -801,5 +899,9 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
 
        .ioctls         = &ioctls[0],
        .ioctl          = av7110_ioctl,
+
+       .vbi_fops.open  = av7110_vbi_reset,
+       .vbi_fops.release = av7110_vbi_reset,
+       .vbi_fops.write = av7110_vbi_write,
 };
 
index 9f51bae..f9d0045 100644 (file)
@@ -127,7 +127,7 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
        saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
        udelay(1);
 
-       result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0);
+       result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
 
        if (result == -ETIMEDOUT)
                budget_av->slot_status = 0;
@@ -145,7 +145,7 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
        saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
        udelay(1);
 
-       result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0);
+       result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
 
        if (result == -ETIMEDOUT)
                budget_av->slot_status = 0;
@@ -192,7 +192,7 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
 {
        struct budget_av *budget_av = (struct budget_av *) ca->data;
        struct saa7146_dev *saa = budget_av->budget.dev;
-       int timeout = 500; // 5 seconds (4.4.6 Ready)
+       int timeout = 50; // 5 seconds (4.4.6 Ready)
 
        if (slot != 0)
                return -EINVAL;
@@ -256,19 +256,37 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
 {
        struct budget_av *budget_av = (struct budget_av *) ca->data;
        struct saa7146_dev *saa = budget_av->budget.dev;
+       int cam_present = 0;
 
        if (slot != 0)
                return -EINVAL;
 
-       if (!budget_av->slot_status) {
+       if (!budget_av->slot_status)
+       {
+               // first of all test the card detect line
                saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
                udelay(1);
                if (saa7146_read(saa, PSR) & MASK_06)
                {
+                       cam_present = 1;
+               }
+               saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+
+               // that is unreliable however, so try and read from IO memory
+               if (!cam_present)
+               {
+                       saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+                       if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
+                       {
+                               cam_present = 1;
+                       }
+               }
+
+               // did we find something?
+               if (cam_present) {
                        printk(KERN_INFO "budget-av: cam inserted\n");
                        budget_av->slot_status = 1;
                }
-               saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
        } else if (!open) {
                saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
                if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
@@ -484,6 +502,140 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
        return 0;
 }
 
+#define MIN2(a,b) ((a) < (b) ? (a) : (b))
+#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
+
+static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
+                                       struct i2c_adapter *i2c,
+                                       struct dvb_frontend_parameters *params)
+{
+       u8 reg0 [2] = { 0x00, 0x00 };
+       u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
+       u8 reg2 [3] = { 0x02, 0x00, 0x00 };
+       int _fband;
+       int first_ZF;
+       int R, A, N, P, M;
+       struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
+       int freq = params->frequency;
+
+       first_ZF = (freq) / 1000;
+
+       if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
+                  abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
+               _fband = 2;
+       else
+               _fband = 3;
+
+       if (_fband == 2) {
+               if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+                                   ((first_ZF >= 1430) && (first_ZF < 1950)))
+                       reg0[1] = 0x07;
+               else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
+                                        ((first_ZF >= 1950) && (first_ZF < 2150)))
+                       reg0[1] = 0x0B;
+       }
+
+       if(_fband == 3) {
+               if (((first_ZF >= 950) && (first_ZF < 1350)) ||
+                                   ((first_ZF >= 1455) && (first_ZF < 1950)))
+                       reg0[1] = 0x07;
+               else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
+                                        ((first_ZF >= 1950) && (first_ZF < 2150)))
+                       reg0[1] = 0x0B;
+               else if ((first_ZF >= 1420) && (first_ZF < 1455))
+                       reg0[1] = 0x0F;
+       }
+
+       if (first_ZF > 1525)
+               reg1[1] |= 0x80;
+       else
+               reg1[1] &= 0x7F;
+
+       if (_fband == 2) {
+               if (first_ZF > 1430) { /* 1430MHZ */
+                       reg1[1] &= 0xCF; /* N2 */
+                       reg2[1] &= 0xCF; /* R2 */
+                       reg2[1] |= 0x10;
+               } else {
+                       reg1[1] &= 0xCF; /* N2 */
+                       reg1[1] |= 0x20;
+                       reg2[1] &= 0xCF; /* R2 */
+                       reg2[1] |= 0x10;
+               }
+       }
+
+       if (_fband == 3) {
+               if ((first_ZF >= 1455) &&
+                                  (first_ZF < 1630)) {
+                       reg1[1] &= 0xCF; /* N2 */
+                       reg1[1] |= 0x20;
+                       reg2[1] &= 0xCF; /* R2 */
+                                  } else {
+                                          if (first_ZF < 1455) {
+                                                  reg1[1] &= 0xCF; /* N2 */
+                                                  reg1[1] |= 0x20;
+                                                  reg2[1] &= 0xCF; /* R2 */
+                                                  reg2[1] |= 0x10;
+                                          } else {
+                                                  if (first_ZF >= 1630) {
+                                                          reg1[1] &= 0xCF; /* N2 */
+                                                          reg2[1] &= 0xCF; /* R2 */
+                                                          reg2[1] |= 0x10;
+                                                  }
+                                          }
+                                  }
+       }
+
+       /* set ports, enable P0 for symbol rates > 4Ms/s */
+       if (params->u.qpsk.symbol_rate >= 4000000)
+               reg1[1] |= 0x0c;
+       else
+               reg1[1] |= 0x04;
+
+       reg2[1] |= 0x0c;
+
+       R = 64;
+       A = 64;
+       P = 64;  //32
+
+       M = (freq * R) / 4;             /* in Mhz */
+       N = (M - A * 1000) / (P * 1000);
+
+       reg1[1] |= (N >> 9) & 0x03;
+       reg1[2]  = (N >> 1) & 0xff;
+       reg1[3]  = (N << 7) & 0x80;
+
+       reg2[1] |= (R >> 8) & 0x03;
+       reg2[2]  = R & 0xFF;    /* R */
+
+       reg1[3] |= A & 0x7f;    /* A */
+
+       if (P == 64)
+               reg1[1] |= 0x40; /* Prescaler 64/65 */
+
+       reg0[1] |= 0x03;
+
+       /* already enabled - do not reenable i2c repeater or TX fails */
+       msg.buf = reg0;
+       msg.len = sizeof(reg0);
+       if (i2c_transfer(i2c, &msg, 1) != 1)
+               return -EIO;
+
+       stv0299_enable_plli2c(fe);
+       msg.buf = reg1;
+       msg.len = sizeof(reg1);
+       if (i2c_transfer(i2c, &msg, 1) != 1)
+               return -EIO;
+
+       stv0299_enable_plli2c(fe);
+       msg.buf = reg2;
+       msg.len = sizeof(reg2);
+       if (i2c_transfer(i2c, &msg, 1) != 1)
+               return -EIO;
+
+       return 0;
+}
+
 static u8 typhoon_cinergy1200s_inittab[] = {
        0x01, 0x15,
        0x02, 0x30,
@@ -553,6 +705,18 @@ static struct stv0299_config cinergy_1200s_config = {
        .pll_set = philips_su1278_ty_ci_pll_set,
 };
 
+static struct stv0299_config cinergy_1200s_1894_0010_config = {
+       .demod_address = 0x68,
+       .inittab = typhoon_cinergy1200s_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP0,
+       .min_delay_ms = 100,
+       .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+       .pll_set = philips_su1278sh2_tua6100_pll_set,
+};
 
 static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
@@ -749,6 +913,15 @@ static void frontend_init(struct budget_av *budget_av)
        switch (saa->pci->subsystem_device) {