Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Jun 2009 04:15:42 +0000 (21:15 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 17 Jun 2009 04:15:42 +0000 (21:15 -0700)
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (425 commits)
  V4L/DVB (11870): gspca - main: VIDIOC_ENUM_FRAMESIZES ioctl added.
  V4L/DVB (12004): poll method lose race condition
  V4L/DVB (11894): flexcop-pci: dmesg visible names broken
  V4L/DVB (11892): Siano: smsendian - declare function as extern
  V4L/DVB (11891): Siano: smscore - bind the GPIO SMS protocol
  V4L/DVB (11890): Siano: smscore - remove redundant code
  V4L/DVB (11889): Siano: smsdvb - add DVB v3 events
  V4L/DVB (11888): Siano: smsusb - remove redundant ifdef
  V4L/DVB (11887): Siano: smscards - add board (target) events
  V4L/DVB (11886): Siano: smscore - fix some new GPIO definitions names
  V4L/DVB (11885): Siano: Add new GPIO management interface
  V4L/DVB (11884): Siano: smssdio - revert to stand alone module
  V4L/DVB (11883): Siano: cards - add two additional (USB) devices
  V4L/DVB (11824): Siano: smsusb - change exit func debug msg
  V4L/DVB (11823): Siano: smsusb - fix typo in module description
  V4L/DVB (11822): Siano: smscore - bug fix at get_device_mode
  V4L/DVB (11821): Siano: smscore - fix isdb-t firmware name
  V4L/DVB (11820): Siano: smscore - fix byte ordering bug
  V4L/DVB (11819): Siano: smscore - fix get_common_buffer bug
  V4L/DVB (11818): Siano: smscards - assign gpio to HPG targets
  ...

254 files changed:
Documentation/dvb/get_dvb_firmware
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/gspca.txt
Documentation/video4linux/pxa_camera.txt
Documentation/video4linux/v4l2-framework.txt
arch/arm/mach-pxa/pcm990-baseboard.c
drivers/media/Kconfig
drivers/media/common/tuners/tuner-simple.c
drivers/media/common/tuners/tuner-types.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/b2c2/flexcop-common.h
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/b2c2/flexcop-i2c.c
drivers/media/dvb/b2c2/flexcop-misc.c
drivers/media/dvb/bt8xx/bt878.c
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_demux.h
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/dw2102.h
drivers/media/dvb/dvb-usb/gp8psk.c
drivers/media/dvb/firewire/firedtv-rc.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/frontends/au8522_dig.c
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/drx397xD.c
drivers/media/dvb/frontends/isl6423.c [new file with mode: 0644]
drivers/media/dvb/frontends/isl6423.h [new file with mode: 0644]
drivers/media/dvb/frontends/lgdt3305.c
drivers/media/dvb/frontends/lgs8gxx.c
drivers/media/dvb/frontends/lnbp21.c
drivers/media/dvb/frontends/mt312.c
drivers/media/dvb/frontends/nxt200x.c
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/stv0900_priv.h
drivers/media/dvb/frontends/stv090x.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv090x.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv090x_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv090x_reg.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110x.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110x.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110x_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110x_reg.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda10048.c
drivers/media/dvb/frontends/tda10048.h
drivers/media/dvb/siano/Makefile
drivers/media/dvb/siano/sms-cards.c
drivers/media/dvb/siano/sms-cards.h
drivers/media/dvb/siano/smscoreapi.c
drivers/media/dvb/siano/smscoreapi.h
drivers/media/dvb/siano/smsdvb.c
drivers/media/dvb/siano/smsendian.c [new file with mode: 0644]
drivers/media/dvb/siano/smsendian.h [new file with mode: 0644]
drivers/media/dvb/siano/smsir.c [new file with mode: 0644]
drivers/media/dvb/siano/smsir.h [new file with mode: 0644]
drivers/media/dvb/siano/smssdio.c [new file with mode: 0644]
drivers/media/dvb/siano/smsusb.c
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_hw.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget.c
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-si470x.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7343.c [new file with mode: 0644]
drivers/media/video/adv7343_regs.h [new file with mode: 0644]
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-core.c
drivers/media/video/au0828/au0828-video.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-i2c.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/cx18-audio.c
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-firmware.c
drivers/media/video/cx18/cx18-av-vbi.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-controls.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-mailbox.h
drivers/media/video/cx18/cx18-queue.c
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-streams.h
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx231xx/cx231xx-avcore.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-i2c.c
drivers/media/video/cx231xx/cx231xx-input.c
drivers/media/video/cx231xx/cx231xx-vbi.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx23885/cimax2.c
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx88/Makefile
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dsp.c [new file with mode: 0644]
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-tvaudio.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-reg.h
drivers/media/video/em28xx/em28xx.h
drivers/media/video/gspca/finepix.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/m5602/Makefile
drivers/media/video/gspca/m5602/m5602_bridge.h
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/m5602/m5602_mt9m111.c
drivers/media/video/gspca/m5602/m5602_mt9m111.h
drivers/media/video/gspca/m5602/m5602_ov7660.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_ov7660.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_ov9650.c
drivers/media/video/gspca/m5602/m5602_ov9650.h
drivers/media/video/gspca/m5602/m5602_po1030.c
drivers/media/video/gspca/m5602/m5602_po1030.h
drivers/media/video/gspca/m5602/m5602_s5k4aa.c
drivers/media/video/gspca/m5602/m5602_s5k4aa.h
drivers/media/video/gspca/m5602/m5602_s5k83a.c
drivers/media/video/gspca/m5602/m5602_s5k83a.h
drivers/media/video/gspca/m5602/m5602_sensor.h
drivers/media/video/gspca/mr97310a.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/sq905.c
drivers/media/video/gspca/sq905c.c
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hexium_gemini.c
drivers/media/video/hexium_orion.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9v022.c
drivers/media/video/mx1_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/mxb.c
drivers/media/video/ov511.c
drivers/media/video/ov511.h
drivers/media/video/pvrusb2/pvrusb2-devattr.c
drivers/media/video/pvrusb2/pvrusb2-devattr.h
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pxa_camera.c
drivers/media/video/s2255drv.c
drivers/media/video/saa7134/Kconfig
drivers/media/video/saa7134/Makefile
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-ts.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/se401.c
drivers/media/video/se401.h
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/soc_camera.c
drivers/media/video/stk-webcam.c
drivers/media/video/tda7432.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/ths7303.c [new file with mode: 0644]
drivers/media/video/tuner-core.c
drivers/media/video/tveeprom.c
drivers/media/video/tvp514x.c
drivers/media/video/usbvideo/konicawc.c
drivers/media/video/usbvideo/quickcam_messenger.c
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_queue.c
drivers/media/video/uvc/uvc_status.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-device.c
drivers/media/video/videobuf-core.c
drivers/media/video/videobuf-dma-contig.c
drivers/media/video/videobuf-dma-sg.c
drivers/media/video/vino.c
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zr364xx.c
include/linux/mmc/sdio_ids.h
include/linux/videodev2.h
include/media/adv7343.h [new file with mode: 0644]
include/media/ir-kbd-i2c.h
include/media/soc_camera.h
include/media/tuner.h
include/media/v4l2-chip-ident.h
include/media/v4l2-device.h
include/media/v4l2-subdev.h

index 2f21ecd4c205fefcefd870abe5c415b49a1b5253..a52adfc9a57fe4d7b8cfbbecfa525df6d91906e1 100644 (file)
@@ -112,7 +112,7 @@ sub tda10045 {
 
 sub tda10046 {
        my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip";
-       my $url = "http://technotrend-online.com/download/software/219/$sourcefile";
+       my $url = "http://www.tt-download.com/download/updates/219/$sourcefile";
        my $hash = "6a7e1e2f2644b162ff0502367553c72d";
        my $outfile = "dvb-fe-tda10046.fw";
        my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -129,8 +129,8 @@ sub tda10046 {
 }
 
 sub tda10046lifeview {
-    my $sourcefile = "Drv_2.11.02.zip";
-    my $url = "http://www.lifeview.com.tw/drivers/pci_card/FlyDVB-T/$sourcefile";
+    my $sourcefile = "7%5Cdrv_2.11.02.zip";
+    my $url = "http://www.lifeview.hk/dbimages/document/$sourcefile";
     my $hash = "1ea24dee4eea8fe971686981f34fd2e0";
     my $outfile = "dvb-fe-tda10046.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -317,7 +317,7 @@ sub nxt2002 {
 
 sub nxt2004 {
     my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip";
-    my $url = "http://www.aver.com/support/Drivers/$sourcefile";
+    my $url = "http://www.avermedia-usa.com/support/Drivers/$sourcefile";
     my $hash = "111cb885b1e009188346d72acfed024c";
     my $outfile = "dvb-fe-nxt2004.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
index 91aa3c0f0dd29b47cd6fff8fbea649e523ce2e75..450b8f8c389bcb5eba41cc21515795429f0c2b5c 100644 (file)
@@ -16,3 +16,8 @@
  15 -> TeVii S470                                          [d470:9022]
  16 -> DVBWorld DVB-S2 2005                                [0001:2005]
  17 -> NetUP Dual DVB-S2 CI                                [1b55:2a2c]
+ 18 -> Hauppauge WinTV-HVR1270                             [0070:2211]
+ 19 -> Hauppauge WinTV-HVR1275                             [0070:2215]
+ 20 -> Hauppauge WinTV-HVR1255                             [0070:2251]
+ 21 -> Hauppauge WinTV-HVR1210                             [0070:2291,0070:2295]
+ 22 -> Mygica X8506 DMB-TH                                 [14f1:8651]
index 71e9db0b26f74d43ab7025caef914ec462f13707..89093f531727766639fc074dcd03cdf528abd7b2 100644 (file)
@@ -78,3 +78,5 @@
  77 -> TBS 8910 DVB-S                                      [8910:8888]
  78 -> Prof 6200 DVB-S                                     [b022:3022]
  79 -> Terratec Cinergy HT PCI MKII                        [153b:1177]
+ 80 -> Hauppauge WinTV-IR Only                             [0070:9290]
+ 81 -> Leadtek WinFast DTV1800 Hybrid                      [107d:6654]
index 78d0a6eed5715809855698d76de27e1bcbde4464..a98a688c11b8b916b0e3e26dba584985b22050e4 100644 (file)
@@ -17,7 +17,7 @@
  16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b]
  17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
  18 -> Hauppauge WinTV HVR 900 (R2)             (em2880)        [2040:6502]
- 19 -> PointNix Intra-Oral Camera               (em2860)
+ 19 -> EM2860/SAA711X Reference Design          (em2860)
  20 -> AMD ATI TV Wonder HD 600                 (em2880)        [0438:b002]
  21 -> eMPIA Technology, Inc. GrabBeeX+ Video Encoder (em2800)        [eb1a:2801]
  22 -> Unknown EM2750/EM2751 webcam grabber     (em2750)        [eb1a:2750,eb1a:2751]
@@ -61,3 +61,7 @@
  63 -> Kaiomy TVnPC U2                          (em2860)        [eb1a:e303]
  64 -> Easy Cap Capture DC-60                   (em2860)
  65 -> IO-DATA GV-MVP/SZ                        (em2820/em2840) [04bb:0515]
+ 66 -> Empire dual TV                           (em2880)
+ 67 -> Terratec Grabby                          (em2860)        [0ccd:0096]
+ 68 -> Terratec AV350                           (em2860)        [0ccd:0084]
+ 69 -> KWorld ATSC 315U HDTV TV Box             (em2882)        [eb1a:a313]
index 6dacf2825259a143de95e0d5fe15a67194b7b0ab..15562427e8a9cb51b7f7611bb38a0bc7975bfa65 100644 (file)
 123 -> Beholder BeholdTV 407                    [0000:4070]
 124 -> Beholder BeholdTV 407 FM                 [0000:4071]
 125 -> Beholder BeholdTV 409                    [0000:4090]
-126 -> Beholder BeholdTV 505 FM/RDS             [0000:5051,0000:505B,5ace:5050]
-127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
+126 -> Beholder BeholdTV 505 FM                 [5ace:5050]
+127 -> Beholder BeholdTV 507 FM / BeholdTV 509 FM [5ace:5070,5ace:5090]
 128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
-129 -> Beholder BeholdTV 607 / BeholdTV 609     [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
+129 -> Beholder BeholdTV 607 FM                 [5ace:6070]
 130 -> Beholder BeholdTV M6                     [5ace:6190]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
 132 -> Genius TVGO AM11MCE
 142 -> Beholder BeholdTV H6                     [5ace:6290]
 143 -> Beholder BeholdTV M63                    [5ace:6191]
 144 -> Beholder BeholdTV M6 Extra               [5ace:6193]
-145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636]
+145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636,1461:f736]
 146 -> ASUSTeK P7131 Analog
 147 -> Asus Tiger 3in1                          [1043:4878]
 148 -> Encore ENLTV-FM v5.3                     [1a7f:2008]
 153 -> Kworld Plus TV Analog Lite PCI           [17de:7128]
 154 -> Avermedia AVerTV GO 007 FM Plus          [1461:f31d]
 155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid  [0070:6706,0070:6708]
-156 -> Hauppauge WinTV-HVR1110r3                [0070:6707,0070:6709,0070:670a]
+156 -> Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid   [0070:6707,0070:6709,0070:670a]
+157 -> Avermedia AVerTV Studio 507UA            [1461:a11b]
+158 -> AVerMedia Cardbus TV/Radio (E501R)       [1461:b7e9]
+159 -> Beholder BeholdTV 505 RDS                [0000:505B]
+160 -> Beholder BeholdTV 507 RDS                [0000:5071]
+161 -> Beholder BeholdTV 507 RDS                [0000:507B]
+162 -> Beholder BeholdTV 607 FM                 [5ace:6071]
+163 -> Beholder BeholdTV 609 FM                 [5ace:6090]
+164 -> Beholder BeholdTV 609 FM                 [5ace:6091]
+165 -> Beholder BeholdTV 607 RDS                [5ace:6072]
+166 -> Beholder BeholdTV 607 RDS                [5ace:6073]
+167 -> Beholder BeholdTV 609 RDS                [5ace:6092]
+168 -> Beholder BeholdTV 609 RDS                [5ace:6093]
index 691d2f37dc57f49267f263d89bb11e985ada7cf7..be67844074dd1f3c31430dc75a70ccc9a53be24a 100644 (file)
@@ -76,3 +76,5 @@ tuner=75 - Philips TEA5761 FM Radio
 tuner=76 - Xceive 5000 tuner
 tuner=77 - TCL tuner MF02GIP-5N-E
 tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
+tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
+tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
index 98529e03a46e196b25f086e604bf0a39bbefceaf..2bcf78896e225a191cc58c23d8636ad92365ecd7 100644 (file)
@@ -163,10 +163,11 @@ sunplus           055f:c650       Mustek MDC5500Z
 zc3xx          055f:d003       Mustek WCam300A
 zc3xx          055f:d004       Mustek WCam300 AN
 conex          0572:0041       Creative Notebook cx11646
-ov519          05a9:0519       OmniVision
+ov519          05a9:0519       OV519 Microphone
 ov519          05a9:0530       OmniVision
-ov519          05a9:4519       OmniVision
+ov519          05a9:4519       Webcam Classic
 ov519          05a9:8519       OmniVision
+ov519          05a9:a518       D-Link DSB-C310 Webcam
 sunplus                05da:1018       Digital Dream Enigma 1.3
 stk014         05e1:0893       Syntek DV4000
 spca561                060b:a001       Maxell Compact Pc PM3
@@ -178,6 +179,7 @@ spca506             06e1:a190       ADS Instant VCD
 ov534          06f8:3002       Hercules Blog Webcam
 ov534          06f8:3003       Hercules Dualpix HD Weblog
 sonixj         06f8:3004       Hercules Classic Silver
+sonixj         06f8:3008       Hercules Deluxe Optical Glass
 spca508                0733:0110       ViewQuest VQ110
 spca508                0130:0130       Clone Digital Webcam 11043
 spca501                0733:0401       Intel Create and Share
@@ -209,6 +211,7 @@ sunplus             08ca:2050       Medion MD 41437
 sunplus                08ca:2060       Aiptek PocketDV5300
 tv8532         0923:010f       ICM532 cams
 mars           093a:050f       Mars-Semi Pc-Camera
+mr97310a       093a:010f       Sakar Digital no. 77379
 pac207         093a:2460       Qtec Webcam 100
 pac207         093a:2461       HP Webcam
 pac207         093a:2463       Philips SPC 220 NC
@@ -265,6 +268,11 @@ sonixj             0c45:60ec       SN9C105+MO4000
 sonixj         0c45:60fb       Surfer NoName
 sonixj         0c45:60fc       LG-LIC300
 sonixj         0c45:60fe       Microdia Audio
+sonixj         0c45:6100       PC Camera (SN9C128)
+sonixj         0c45:610a       PC Camera (SN9C128)
+sonixj         0c45:610b       PC Camera (SN9C128)
+sonixj         0c45:610c       PC Camera (SN9C128)
+sonixj         0c45:610e       PC Camera (SN9C128)
 sonixj         0c45:6128       Microdia/Sonix SNP325
 sonixj         0c45:612a       Avant Camera
 sonixj         0c45:612c       Typhoon Rasy Cam 1.3MPix
index b1137f9a53eb28efb64fab2a1bbcdef53380f086..4f6d0ca019564f86b4dfed75fff7b9597dbd838b 100644 (file)
@@ -26,6 +26,55 @@ Global video workflow
 
      Once the last buffer is filled in, the QCI interface stops.
 
+  c) Capture global finite state machine schema
+
+      +----+                             +---+  +----+
+      | DQ |                             | Q |  | DQ |
+      |    v                             |   v  |    v
+    +-----------+                     +------------------------+
+    |   STOP    |                     | Wait for capture start |
+    +-----------+         Q           +------------------------+
++-> | QCI: stop | ------------------> | QCI: run               | <------------+
+|   | DMA: stop |                     | DMA: stop              |              |
+|   +-----------+             +-----> +------------------------+              |
+|                            /                            |                   |
+|                           /             +---+  +----+   |                   |
+|capture list empty        /              | Q |  | DQ |   | QCI Irq EOF       |
+|                         /               |   v  |    v   v                   |
+|   +--------------------+             +----------------------+               |
+|   | DMA hotlink missed |             |    Capture running   |               |
+|   +--------------------+             +----------------------+               |
+|   | QCI: run           |     +-----> | QCI: run             | <-+           |
+|   | DMA: stop          |    /        | DMA: run             |   |           |
+|   +--------------------+   /         +----------------------+   | Other     |
+|     ^                     /DMA still            |               | channels  |
+|     | capture list       /  running             | DMA Irq End   | not       |
+|     | not empty         /                       |               | finished  |
+|     |                  /                        v               | yet       |
+|   +----------------------+           +----------------------+   |           |
+|   |  Videobuf released   |           |  Channel completed   |   |           |
+|   +----------------------+           +----------------------+   |           |
++-- | QCI: run             |           | QCI: run             | --+           |
+    | DMA: run             |           | DMA: run             |               |
+    +----------------------+           +----------------------+               |
+               ^                      /           |                           |
+               |          no overrun /            | overrun                   |
+               |                    /             v                           |
+    +--------------------+         /   +----------------------+               |
+    |  Frame completed   |        /    |     Frame overran    |               |
+    +--------------------+ <-----+     +----------------------+ restart frame |
+    | QCI: run           |             | QCI: stop            | --------------+
+    | DMA: run           |             | DMA: stop            |
+    +--------------------+             +----------------------+
+
+    Legend: - each box is a FSM state
+            - each arrow is the condition to transition to another state
+            - an arrow with a comment is a mandatory transition (no condition)
+            - arrow "Q" means : a buffer was enqueued
+            - arrow "DQ" means : a buffer was dequeued
+            - "QCI: stop" means the QCI interface is not enabled
+            - "DMA: stop" means all 3 DMA channels are stopped
+            - "DMA: run" means at least 1 DMA channel is still running
 
 DMA usage
 ---------
index 854808b67faed03f209291ae2947be5f051e8af6..d54c1e4c6a9cec5f0cb8e8a2a53517b0bac662a7 100644 (file)
@@ -89,6 +89,11 @@ from dev (driver name followed by the bus_id, to be precise). If you set it
 up before calling v4l2_device_register then it will be untouched. If dev is
 NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
 
+You can use v4l2_device_set_name() to set the name based on a driver name and
+a driver-global atomic_t instance. This will generate names like ivtv0, ivtv1,
+etc. If the name ends with a digit, then it will insert a dash: cx18-0,
+cx18-1, etc. This function returns the instance number.
+
 The first 'dev' argument is normally the struct device pointer of a pci_dev,
 usb_interface or platform_device. It is rare for dev to be NULL, but it happens
 with ISA devices or when one device creates multiple PCI devices, thus making
index 095521e9ee246755980af5a59f76986f89ecb59c..01791d74e08ec543e6aab65394c137921a6552f4 100644 (file)
@@ -380,12 +380,12 @@ static struct pca953x_platform_data pca9536_data = {
        .gpio_base      = NR_BUILTIN_GPIO,
 };
 
-static int gpio_bus_switch;
+static int gpio_bus_switch = -EINVAL;
 
 static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
-               unsigned long flags)
+                                      unsigned long flags)
 {
-       if (gpio_bus_switch <= 0) {
+       if (gpio_bus_switch < 0) {
                if (flags == SOCAM_DATAWIDTH_10)
                        return 0;
                else
@@ -404,25 +404,34 @@ static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link)
 {
        int ret;
 
-       if (!gpio_bus_switch) {
+       if (gpio_bus_switch < 0) {
                ret = gpio_request(NR_BUILTIN_GPIO, "camera");
                if (!ret) {
                        gpio_bus_switch = NR_BUILTIN_GPIO;
                        gpio_direction_output(gpio_bus_switch, 0);
-               } else
-                       gpio_bus_switch = -EINVAL;
+               }
        }
 
-       if (gpio_bus_switch > 0)
+       if (gpio_bus_switch >= 0)
                return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
        else
                return SOCAM_DATAWIDTH_10;
 }
 
+static void pcm990_camera_free_bus(struct soc_camera_link *link)
+{
+       if (gpio_bus_switch < 0)
+               return;
+
+       gpio_free(gpio_bus_switch);
+       gpio_bus_switch = -EINVAL;
+}
+
 static struct soc_camera_link iclink = {
        .bus_id = 0, /* Must match with the camera ID above */
        .query_bus_param = pcm990_camera_query_bus_param,
        .set_bus_param = pcm990_camera_set_bus_param,
+       .free_bus = pcm990_camera_free_bus,
 };
 
 /* Board I2C devices. */
index 223c36ede5ae66e3552682c63bc9fc9df4394d57..ba69beeb0e21a850aab9d1a49b11c409b332f44e 100644 (file)
@@ -2,8 +2,14 @@
 # Multimedia device configuration
 #
 
-menu "Multimedia devices"
+menuconfig MEDIA_SUPPORT
+       tristate "Multimedia support"
        depends on HAS_IOMEM
+       help
+         If you want to use Video for Linux, DVB for Linux, or DAB adapters,
+         enable this option and other options below.
+
+if MEDIA_SUPPORT
 
 comment "Multimedia core support"
 
@@ -136,4 +142,4 @@ config USB_DABUSB
          module will be called dabusb.
 endif # DAB
 
-endmenu
+endif # MEDIA_SUPPORT
index 78412c9c424a13e492a59ad467368716755be6b2..149d54cdf7b97a4ff92107e3afffbb1c773a1ddc 100644 (file)
@@ -416,6 +416,24 @@ static int simple_std_setup(struct dvb_frontend *fe,
        return 0;
 }
 
+static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
+{
+       struct tuner_simple_priv *priv = fe->tuner_priv;
+       int rc;
+       u8 buffer[2];
+
+       buffer[0] = (config & ~0x38) | 0x18;
+       buffer[1] = aux;
+
+       tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+
+       rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
+       if (2 != rc)
+               tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
+
+       return rc == 2 ? 0 : rc;
+}
+
 static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
                            u16 div, u8 config, u8 cb)
 {
@@ -424,17 +442,10 @@ static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
 
        switch (priv->type) {
        case TUNER_LG_TDVS_H06XF:
-               /* Set the Auxiliary Byte. */
-               buffer[0] = buffer[2];
-               buffer[0] &= ~0x20;
-               buffer[0] |= 0x18;
-               buffer[1] = 0x20;
-               tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);
-
-               rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
-               if (2 != rc)
-                       tuner_warn("i2c i/o error: rc == %d "
-                                  "(should be 2)\n", rc);
+               simple_set_aux_byte(fe, config, 0x20);
+               break;
+       case TUNER_PHILIPS_FQ1216LME_MK3:
+               simple_set_aux_byte(fe, config, 0x60); /* External AGC */
                break;
        case TUNER_MICROTUNE_4042FI5:
        {
@@ -506,6 +517,11 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
        case TUNER_THOMSON_DTT761X:
                buffer[3] = 0x39;
                break;
+       case TUNER_PHILIPS_FQ1216LME_MK3:
+               tuner_err("This tuner doesn't have FM\n");
+               /* Set the low band for sanity, since it covers 88-108 MHz */
+               buffer[3] = 0x01;
+               break;
        case TUNER_MICROTUNE_4049FM5:
        default:
                buffer[3] = 0xa4;
@@ -678,12 +694,12 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
                return 0;
        }
 
-       /* Bandswitch byte */
-       simple_radio_bandswitch(fe, &buffer[0]);
-
        buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
                    TUNER_RATIO_SELECT_50; /* 50 kHz step */
 
+       /* Bandswitch byte */
+       simple_radio_bandswitch(fe, &buffer[0]);
+
        /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
           freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
           freq * (1/800) */
index 7c0bc064c008966b05316c842657dec7ae0972c7..6a7f1a417c278eff34d835029b4894fde8cedd48 100644 (file)
@@ -578,6 +578,31 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = {
        },
 };
 
+/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */
+
+static struct tuner_range tuner_fm1216mk5_pal_ranges[] = {
+       { 16 * 158.00 /*MHz*/, 0xce, 0x01, },
+       { 16 * 441.00 /*MHz*/, 0xce, 0x02, },
+       { 16 * 864.00        , 0xce, 0x04, },
+};
+
+static struct tuner_params tuner_fm1216mk5_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_PAL,
+               .ranges = tuner_fm1216mk5_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges),
+               .cb_first_if_lower_freq = 1,
+               .has_tda9887 = 1,
+               .port1_active = 1,
+               .port2_active = 1,
+               .port2_invert_for_secam_lc = 1,
+               .port1_fm_high_sensitivity = 1,
+               .default_top_mid = -2,
+               .default_top_secam_mid = -2,
+               .default_top_secam_high = -2,
+       },
+};
+
 /* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */
 
 static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
@@ -1254,6 +1279,28 @@ static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
        },
 };
 
+/* 80-89 */
+/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */
+
+static struct tuner_params tuner_fq1216lme_mk3_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_PAL,
+               .ranges = tuner_fm1216me_mk3_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
+               .cb_first_if_lower_freq = 1, /* not specified, but safe to do */
+               .has_tda9887 = 1, /* TDA9886 */
+               .port1_active = 1,
+               .port2_active = 1,
+               .port2_invert_for_secam_lc = 1,
+               .default_top_low = 4,
+               .default_top_mid = 4,
+               .default_top_high = 4,
+               .default_top_secam_low = 4,
+               .default_top_secam_mid = 4,
+               .default_top_secam_high = 4,
+       },
+};
+
 /* --------------------------------------------------------------------- */
 
 struct tunertype tuners[] = {
@@ -1694,6 +1741,18 @@ struct tunertype tuners[] = {
                .initdata = tua603x_agc112,
                .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
        },
+               [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */
+               .name   = "Philips PAL/SECAM multi (FM1216 MK5)",
+               .params = tuner_fm1216mk5_params,
+               .count  = ARRAY_SIZE(tuner_fm1216mk5_params),
+       },
+
+       /* 80-89 */
+       [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */
+               .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough",
+               .params = tuner_fq1216lme_mk3_params,
+               .count  = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
+       },
 };
 EXPORT_SYMBOL(tuners);
 
index 7636c33bc1e97dc8ee783f3ef353c87f5f0c3042..b6da9c3873fef280ba89d00234053d3a62b11ec6 100644 (file)
@@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
 static int no_poweroff;
 module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
        "1 keep device energized and with tuner ready all the times.\n"
        "  Faster, but consumes more power and keeps the device hotter\n");
 
@@ -272,7 +272,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
                fname = firmware_name;
 
        tuner_dbg("Reading firmware %s\n", fname);
-       rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev);
+       rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
        if (rc < 0) {
                if (rc == -ENOENT)
                        tuner_err("Error: firmware %s not found.\n",
@@ -917,22 +917,29 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
         * that xc2028 will be in a safe state.
         * Maybe this might also be needed for DTV.
         */
-       if (new_mode == T_ANALOG_TV) {
+       if (new_mode == T_ANALOG_TV)
                rc = send_seq(priv, {0x00, 0x00});
-       } else if (priv->cur_fw.type & ATSC) {
-               offset = 1750000;
-       } else {
-               offset = 2750000;
+
+       /*
+        * Digital modes require an offset to adjust to the
+        * proper frequency.
+        * Analog modes require offset = 0
+        */
+       if (new_mode == T_DIGITAL_TV) {
+               /* Sets the offset according with firmware */
+               if (priv->cur_fw.type & DTV6)
+                       offset = 1750000;
+               else if (priv->cur_fw.type & DTV7)
+                       offset = 2250000;
+               else    /* DTV8 or DTV78 */
+                       offset = 2750000;
+
                /*
-                * We must adjust the offset by 500kHz in two cases in order
-                * to correctly center the IF output:
-                * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
-                *    selected and a 7MHz channel is tuned;
-                * 2) When tuning a VHF channel with DTV78 firmware.
+                * We must adjust the offset by 500kHz  when
+                * tuning a 7MHz VHF channel with DTV78 firmware
+                * (used in Australia, Italy and Germany)
                 */
-               if (((priv->cur_fw.type & DTV7) &&
-                    (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
-                   ((priv->cur_fw.type & DTV78) && freq < 470000000))
+               if ((priv->cur_fw.type & DTV78) && freq < 470000000)
                        offset -= 500000;
        }
 
@@ -991,7 +998,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
                if (priv->ctrl.input1)
                        type |= INPUT1;
                return generic_set_freq(fe, (625l * p->frequency) / 10,
-                               T_ANALOG_TV, type, 0, 0);
+                               T_RADIO, type, 0, 0);
        }
 
        /* if std is not defined, choose one */
@@ -1022,21 +1029,20 @@ static int xc2028_set_params(struct dvb_frontend *fe,
        switch(fe->ops.info.type) {
        case FE_OFDM:
                bw = p->u.ofdm.bandwidth;
-               break;
-       case FE_QAM:
-               tuner_info("WARN: There are some reports that "
-                          "QAM 6 MHz doesn't work.\n"
-                          "If this works for you, please report by "
-                          "e-mail to: v4l-dvb-maintainer@linuxtv.org\n");
-               bw = BANDWIDTH_6_MHZ;
-               type |= QAM;
+               /*
+                * The only countries with 6MHz seem to be Taiwan/Uruguay.
+                * Both seem to require QAM firmware for OFDM decoding
+                * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
+                */
+               if (bw == BANDWIDTH_6_MHZ)
+                       type |= QAM;
                break;
        case FE_ATSC:
                bw = BANDWIDTH_6_MHZ;
                /* The only ATSC firmware (at least on v2.7) is D2633 */
                type |= ATSC | D2633;
                break;
-       /* DVB-S is not supported */
+       /* DVB-S and pure QAM (FE_QAM) are not supported */
        default:
                return -EINVAL;
        }
index b54598550dc43da789cc7b6fdbc6acf3792aa5c8..f4ffcdc9b848919c5953372375eedacabb0210b6 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (c) 2007 Xceive Corporation
  *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.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
@@ -36,14 +37,20 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
+       "\t\t1 keep device energized and with tuner ready all the times.\n"
+       "\t\tFaster, but consumes more power and keeps the device hotter");
+
 static DEFINE_MUTEX(xc5000_list_mutex);
 static LIST_HEAD(hybrid_tuner_instance_list);
 
 #define dprintk(level, fmt, arg...) if (debug >= level) \
        printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
-#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
-#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
+#define XC5000_DEFAULT_FIRMWARE_SIZE 12401
 
 struct xc5000_priv {
        struct tuner_i2c_props i2c_props;
@@ -83,11 +90,11 @@ struct xc5000_priv {
 #define XREG_D_CODE       0x04
 #define XREG_IF_OUT       0x05
 #define XREG_SEEK_MODE    0x07
-#define XREG_POWER_DOWN   0x0A
+#define XREG_POWER_DOWN   0x0A /* Obsolete */
 #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
 #define XREG_SMOOTHEDCVBS 0x0E
 #define XREG_XTALFREQ     0x0F
-#define XREG_FINERFFREQ   0x10
+#define XREG_FINERFREQ    0x10
 #define XREG_DDIMODE      0x11
 
 #define XREG_ADC_ENV      0x00
@@ -100,6 +107,7 @@ struct xc5000_priv {
 #define XREG_VERSION      0x07
 #define XREG_PRODUCT_ID   0x08
 #define XREG_BUSY         0x09
+#define XREG_BUILD        0x0D
 
 /*
    Basic firmware description. This will remain with
@@ -191,27 +199,36 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
        {"FM Radio-INPUT1",   0x0208, 0x9002}
 };
 
-static int  xc5000_is_firmware_loaded(struct dvb_frontend *fe);
-static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-static void xc5000_TunerReset(struct dvb_frontend *fe);
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
+static int xc5000_TunerReset(struct dvb_frontend *fe);
 
 static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
 {
-       return xc5000_writeregs(priv, buf, len)
-               ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+                              .flags = 0, .buf = buf, .len = len };
+
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+               printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
+               return XC_RESULT_I2C_WRITE_FAILURE;
+       }
+       return XC_RESULT_SUCCESS;
 }
 
+/* This routine is never used because the only time we read data from the
+   i2c bus is when we read registers, and we want that to be an atomic i2c
+   transaction in case we are on a multi-master bus */
 static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
 {
-       return xc5000_readregs(priv, buf, len)
-               ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
-}
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+               .flags = I2C_M_RD, .buf = buf, .len = len };
 
-static int xc_reset(struct dvb_frontend *fe)
-{
-       xc5000_TunerReset(fe);
-       return XC_RESULT_SUCCESS;
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+               printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
+               return -EREMOTEIO;
+       }
+       return 0;
 }
 
 static void xc_wait(int wait_ms)
@@ -219,7 +236,7 @@ static void xc_wait(int wait_ms)
        msleep(wait_ms);
 }
 
-static void xc5000_TunerReset(struct dvb_frontend *fe)
+static int xc5000_TunerReset(struct dvb_frontend *fe)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
        int ret;
@@ -232,16 +249,21 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
                                           priv->i2c_props.adap->algo_data,
                                           DVB_FRONTEND_COMPONENT_TUNER,
                                           XC5000_TUNER_RESET, 0);
-               if (ret)
+               if (ret) {
                        printk(KERN_ERR "xc5000: reset failed\n");
-       } else
+                       return XC_RESULT_RESET_FAILURE;
+               }
+       } else {
                printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+               return XC_RESULT_RESET_FAILURE;
+       }
+       return XC_RESULT_SUCCESS;
 }
 
 static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
 {
        u8 buf[4];
-       int WatchDogTimer = 5;
+       int WatchDogTimer = 100;
        int result;
 
        buf[0] = (regAddr >> 8) & 0xFF;
@@ -263,7 +285,7 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
                                                /* busy flag cleared */
                                        break;
                                        } else {
-                                               xc_wait(100); /* wait 5 ms */
+                                               xc_wait(5); /* wait 5 ms */
                                                WatchDogTimer--;
                                        }
                                }
@@ -276,25 +298,6 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
        return result;
 }
 
-static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
-{
-       u8 buf[2];
-       int result;
-
-       buf[0] = (regAddr >> 8) & 0xFF;
-       buf[1] = regAddr & 0xFF;
-       result = xc_send_i2c_data(priv, buf, 2);
-       if (result != XC_RESULT_SUCCESS)
-               return result;
-
-       result = xc_read_i2c_data(priv, buf, 2);
-       if (result != XC_RESULT_SUCCESS)
-               return result;
-
-       *i2cData = buf[0] * 256 + buf[1];
-       return result;
-}
-
 static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
@@ -309,7 +312,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
                len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
                if (len == 0x0000) {
                        /* RESET command */
-                       result = xc_reset(fe);
+                       result = xc5000_TunerReset(fe);
                        index += 2;
                        if (result != XC_RESULT_SUCCESS)
                                return result;
@@ -371,15 +374,6 @@ static int xc_SetTVStandard(struct xc5000_priv *priv,
        return ret;
 }
 
-static int xc_shutdown(struct xc5000_priv *priv)
-{
-       return XC_RESULT_SUCCESS;
-       /* Fixme: cannot bring tuner back alive once shutdown
-        *        without reloading the driver modules.
-        *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
-        */
-}
-
 static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
 {
        dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
@@ -408,7 +402,10 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
 
        freq_code = (u16)(freq_hz / 15625);
 
-       return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+       /* Starting in firmware version 1.1.44, Xceive recommends using the
+          FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+          only be used for fast scanning for channel lock) */
+       return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
 }
 
 
@@ -424,7 +421,7 @@ static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
 
 static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
 {
-       return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
+       return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
 }
 
 static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
@@ -433,8 +430,8 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
        u16 regData;
        u32 tmp;
 
-       result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
-       if (result)
+       result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
+       if (result != XC_RESULT_SUCCESS)
                return result;
 
        tmp = (u32)regData;
@@ -444,7 +441,7 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
 
 static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
 {
-       return xc_read_reg(priv, XREG_LOCK, lock_status);
+       return xc5000_readreg(priv, XREG_LOCK, lock_status);
 }
 
 static int xc_get_version(struct xc5000_priv *priv,
@@ -454,8 +451,8 @@ static int xc_get_version(struct xc5000_priv *priv,
        u16 data;
        int result;
 
-       result = xc_read_reg(priv, XREG_VERSION, &data);
-       if (result)
+       result = xc5000_readreg(priv, XREG_VERSION, &data);
+       if (result != XC_RESULT_SUCCESS)
                return result;
 
        (*hw_majorversion) = (data >> 12) & 0x0F;
@@ -466,13 +463,18 @@ static int xc_get_version(struct xc5000_priv *priv,
        return 0;
 }
 
+static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
+{
+       return xc5000_readreg(priv, XREG_BUILD, buildrev);
+}
+
 static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
 {
        u16 regData;
        int result;
 
-       result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
-       if (result)
+       result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+       if (result != XC_RESULT_SUCCESS)
                return result;
 
        (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
@@ -481,12 +483,12 @@ static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
 
 static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
 {
-       return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
+       return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
 }
 
 static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
 {
-       return xc_read_reg(priv, XREG_QUALITY, quality);
+       return xc5000_readreg(priv, XREG_QUALITY, quality);
 }
 
 static u16 WaitForLock(struct xc5000_priv *priv)
@@ -504,7 +506,9 @@ static u16 WaitForLock(struct xc5000_priv *priv)
        return lockState;
 }
 
-static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
+#define XC_TUNE_ANALOG  0
+#define XC_TUNE_DIGITAL 1
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
 {
        int found = 0;
 
@@ -513,8 +517,10 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
        if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
                return 0;
 
-       if (WaitForLock(priv) == 1)
-               found = 1;
+       if (mode == XC_TUNE_ANALOG) {
+               if (WaitForLock(priv) == 1)
+                       found = 1;
+       }
 
        return found;
 }
@@ -536,32 +542,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
        }
 
        *val = (bval[0] << 8) | bval[1];
-       return 0;
-}
-
-static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
-{
-       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
-               .flags = 0, .buf = buf, .len = len };
-
-       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-               printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
-                       (int)len);
-               return -EREMOTEIO;
-       }
-       return 0;
-}
-
-static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
-{
-       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
-               .flags = I2C_M_RD, .buf = buf, .len = len };
-
-       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-               printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len);
-               return -EREMOTEIO;
-       }
-       return 0;
+       return XC_RESULT_SUCCESS;
 }
 
 static int xc5000_fwupload(struct dvb_frontend *fe)
@@ -575,13 +556,13 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
                XC5000_DEFAULT_FIRMWARE);
 
        ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
-               &priv->i2c_props.adap->dev);
+               priv->i2c_props.adap->dev.parent);
        if (ret) {
                printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
                ret = XC_RESULT_RESET_FAILURE;
                goto out;
        } else {
-               printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
+               printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
                       fw->size);
                ret = XC_RESULT_SUCCESS;
        }
@@ -590,8 +571,9 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
                printk(KERN_ERR "xc5000: firmware incorrect size\n");
                ret = XC_RESULT_RESET_FAILURE;
        } else {
-               printk(KERN_INFO "xc5000: firmware upload\n");
+               printk(KERN_INFO "xc5000: firmware uploading...\n");
                ret = xc_load_i2c_sequence(fe,  fw->data);
+               printk(KERN_INFO "xc5000: firmware upload complete...\n");
        }
 
 out:
@@ -609,6 +591,7 @@ static void xc_debug_dump(struct xc5000_priv *priv)
        u16 quality;
        u8 hw_majorversion = 0, hw_minorversion = 0;
        u8 fw_majorversion = 0, fw_minorversion = 0;
+       u16 fw_buildversion = 0;
 
        /* Wait for stats to stabilize.
         * Frame Lines needs two frame times after initial lock
@@ -628,9 +611,10 @@ static void xc_debug_dump(struct xc5000_priv *priv)
 
        xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
                &fw_majorversion, &fw_minorversion);
-       dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+       xc_get_buildversion(priv,  &fw_buildversion);
+       dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n",
                hw_majorversion, hw_minorversion,
-               fw_majorversion, fw_minorversion);
+               fw_majorversion, fw_minorversion, fw_buildversion);
 
        xc_get_hsync_freq(priv,  &hsync_freq_hz);
        dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
@@ -648,27 +632,57 @@ static int xc5000_set_params(struct dvb_frontend *fe,
        struct xc5000_priv *priv = fe->tuner_priv;
        int ret;
 
+       if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
+               xc_load_fw_and_init_tuner(fe);
+
        dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
 
-       switch (params->u.vsb.modulation) {
-       case VSB_8:
-       case VSB_16:
-               dprintk(1, "%s() VSB modulation\n", __func__);
+       if (fe->ops.info.type == FE_ATSC) {
+               dprintk(1, "%s() ATSC\n", __func__);
+               switch (params->u.vsb.modulation) {
+               case VSB_8:
+               case VSB_16:
+                       dprintk(1, "%s() VSB modulation\n", __func__);
+                       priv->rf_mode = XC_RF_MODE_AIR;
+                       priv->freq_hz = params->frequency - 1750000;
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = DTV6;
+                       break;
+               case QAM_64:
+               case QAM_256:
+               case QAM_AUTO:
+                       dprintk(1, "%s() QAM modulation\n", __func__);
+                       priv->rf_mode = XC_RF_MODE_CABLE;
+                       priv->freq_hz = params->frequency - 1750000;
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = DTV6;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else if (fe->ops.info.type == FE_OFDM) {
+               dprintk(1, "%s() OFDM\n", __func__);
+               switch (params->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = DTV6;
+                       priv->freq_hz = params->frequency - 1750000;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n");
+                       return -EINVAL;
+               case BANDWIDTH_8_MHZ:
+                       priv->bandwidth = BANDWIDTH_8_MHZ;
+                       priv->video_standard = DTV8;
+                       priv->freq_hz = params->frequency - 2750000;
+                       break;
+               default:
+                       printk(KERN_ERR "xc5000 bandwidth not set!\n");
+                       return -EINVAL;
+               }
                priv->rf_mode = XC_RF_MODE_AIR;
-               priv->freq_hz = params->frequency - 1750000;
-               priv->bandwidth = BANDWIDTH_6_MHZ;
-               priv->video_standard = DTV6;
-               break;
-       case QAM_64:
-       case QAM_256:
-       case QAM_AUTO:
-               dprintk(1, "%s() QAM modulation\n", __func__);
-               priv->rf_mode = XC_RF_MODE_CABLE;
-               priv->freq_hz = params->frequency - 1750000;
-               priv->bandwidth = BANDWIDTH_6_MHZ;
-               priv->video_standard = DTV6;
-               break;
-       default:
+       } else {
+               printk(KERN_ERR "xc5000 modulation type not supported!\n");
                return -EINVAL;
        }
 
@@ -698,7 +712,7 @@ static int xc5000_set_params(struct dvb_frontend *fe,
                return -EIO;
        }
 
-       xc_tune_channel(priv, priv->freq_hz);
+       xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
 
        if (debug)
                xc_debug_dump(priv);
@@ -725,8 +739,6 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
        return ret;
 }
 
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
-
 static int xc5000_set_analog_params(struct dvb_frontend *fe,
        struct analog_parameters *params)
 {
@@ -807,7 +819,7 @@ tune_channel:
                return -EREMOTEIO;
        }
 
-       xc_tune_channel(priv, priv->freq_hz);
+       xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
 
        if (debug)
                xc_debug_dump(priv);
@@ -875,18 +887,18 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
 
 static int xc5000_sleep(struct dvb_frontend *fe)
 {
-       struct xc5000_priv *priv = fe->tuner_priv;
        int ret;
 
        dprintk(1, "%s()\n", __func__);
 
-       /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
-        * once shutdown without reloading the driver. Maybe I am not
-        * doing something right.
-        *
-        */
+       /* Avoid firmware reload on slow devices */
+       if (no_poweroff)
+               return 0;
 
-       ret = xc_shutdown(priv);
+       /* According to Xceive technical support, the "powerdown" register
+          was removed in newer versions of the firmware.  The "supported"
+          way to sleep the tuner is to pull the reset pin low for 10ms */
+       ret = xc5000_TunerReset(fe);
        if (ret != XC_RESULT_SUCCESS) {
                printk(KERN_ERR
                        "xc5000: %s() unable to shutdown tuner\n",
@@ -991,7 +1003,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
        /* Check if firmware has been loaded. It is possible that another
           instance of the driver has loaded the firmware.
         */
-       if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+       if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
                goto fail;
 
        switch (id) {
index 3e1c472092ab238af0e26e1ef89917b220477aa7..9e2148a199676e0c45fb1472ba69b79f61a0e5b8 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-common.h - common header file for device-specific source files also.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-common.h - common header file for device-specific source files
+ * see flexcop.c for copyright information
  */
 #ifndef __FLEXCOP_COMMON_H__
 #define __FLEXCOP_COMMON_H__
index f7afab5944cfc2395c8b30592dc9740da22325cc..efb4a6c2b57a5d39cf9c70a5cef455a9dbb528e4 100644 (file)
@@ -1,34 +1,27 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
+ * see flexcop.c for copyright information
  */
 #include <media/tuner.h>
-
 #include "flexcop.h"
-
-#include "stv0299.h"
-#include "mt352.h"
-#include "nxt200x.h"
-#include "bcm3510.h"
-#include "stv0297.h"
 #include "mt312.h"
-#include "lgdt330x.h"
-#include "dvb-pll.h"
-#include "tuner-simple.h"
-
+#include "stv0299.h"
 #include "s5h1420.h"
 #include "itd1000.h"
-
-#include "cx24123.h"
 #include "cx24113.h"
-
+#include "cx24123.h"
 #include "isl6421.h"
+#include "mt352.h"
+#include "bcm3510.h"
+#include "nxt200x.h"
+#include "dvb-pll.h"
+#include "lgdt330x.h"
+#include "tuner-simple.h"
+#include "stv0297.h"
 
 /* lnb control */
-
+#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE)
 static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct flexcop_device *fc = fe->dvb->priv;
@@ -37,65 +30,62 @@ static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage
 
        v = fc->read_ibi_reg(fc, misc_204);
        switch (voltage) {
-               case SEC_VOLTAGE_OFF:
-                       v.misc_204.ACPI1_sig = 1;
-                       break;
-               case SEC_VOLTAGE_13:
-                       v.misc_204.ACPI1_sig = 0;
-                       v.misc_204.LNB_L_H_sig = 0;
-                       break;
-               case SEC_VOLTAGE_18:
-                       v.misc_204.ACPI1_sig = 0;
-                       v.misc_204.LNB_L_H_sig = 1;
-                       break;
-               default:
-                       err("unknown SEC_VOLTAGE value");
-                       return -EINVAL;
+       case SEC_VOLTAGE_OFF:
+               v.misc_204.ACPI1_sig = 1;
+               break;
+       case SEC_VOLTAGE_13:
+               v.misc_204.ACPI1_sig = 0;
+               v.misc_204.LNB_L_H_sig = 0;
+               break;
+       case SEC_VOLTAGE_18:
+               v.misc_204.ACPI1_sig = 0;
+               v.misc_204.LNB_L_H_sig = 1;
+               break;
+       default:
+               err("unknown SEC_VOLTAGE value");
+               return -EINVAL;
        }
        return fc->write_ibi_reg(fc, misc_204, v);
 }
+#endif
 
+#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \
+       || defined(CONFIG_DVB_MT312_MODULE)
 static int flexcop_sleep(struct dvb_frontend* fe)
 {
        struct flexcop_device *fc = fe->dvb->priv;
-/*     flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
-
        if (fc->fe_sleep)
                return fc->fe_sleep(fe);
-
-/*     v.misc_204.ACPI3_sig = 1;
-       fc->write_ibi_reg(fc,misc_204,v);*/
-
        return 0;
 }
+#endif
 
+/* SkyStar2 DVB-S rev 2.3 */
+#if defined(CONFIG_DVB_MT312_MODULE)
 static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
 {
-       /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
+/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
        struct flexcop_device *fc = fe->dvb->priv;
        flexcop_ibi_value v;
        u16 ax;
        v.raw = 0;
-
        deb_tuner("tone = %u\n",tone);
 
        switch (tone) {
-               case SEC_TONE_ON:
-                       ax = 0x01ff;
-                       break;
-               case SEC_TONE_OFF:
-                       ax = 0;
-                       break;
-               default:
-                       err("unknown SEC_TONE value");
-                       return -EINVAL;
+       case SEC_TONE_ON:
+               ax = 0x01ff;
+               break;
+       case SEC_TONE_OFF:
+               ax = 0;
+               break;
+       default:
+               err("unknown SEC_TONE value");
+               return -EINVAL;
        }
 
        v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
-
        v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
        v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
-
        return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
 }
 
@@ -110,17 +100,16 @@ static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
 static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
 {
        int i, par = 1, d;
-
        for (i = 7; i >= 0; i--) {
                d = (data >> i) & 1;
                par ^= d;
                flexcop_diseqc_send_bit(fe, d);
        }
-
        flexcop_diseqc_send_bit(fe, par);
 }
 
-static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
+static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
+       int len, u8 *msg, unsigned long burst)
 {
        int i;
 
@@ -129,7 +118,6 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
 
        for (i = 0; i < len; i++)
                flexcop_diseqc_send_byte(fe,msg[i]);
-
        mdelay(16);
 
        if (burst != -1) {
@@ -146,50 +134,110 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
        return 0;
 }
 
-static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
+       struct dvb_diseqc_master_cmd *cmd)
 {
        return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
 }
 
-static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
+       fe_sec_mini_cmd_t minicmd)
 {
        return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
 }
 
-/* dvb-s stv0299 */
-static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+static struct mt312_config skystar23_samsung_tbdu18132_config = {
+       .demod_address = 0x0e,
+};
+
+static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       u8 buf[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf,
+       .len = sizeof(buf) };
+       struct flexcop_device *fc = fe->dvb->priv;
+       div = (params->frequency + (125/2)) / 125;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = (div >> 0) & 0xff;
+       buf[2] = 0x84 | ((div >> 10) & 0x60);
+       buf[3] = 0x80;
+
+       if (params->frequency < 1550000)
+               buf[3] |= 0x02;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static int skystar2_rev23_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
+       if (fc->fe != NULL) {
+               struct dvb_frontend_ops *ops = &fc->fe->ops;
+               ops->tuner_ops.set_params   =
+                       skystar23_samsung_tbdu18132_tuner_set_params;
+               ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+               ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
+               ops->set_tone               = flexcop_set_tone;
+               ops->set_voltage            = flexcop_set_voltage;
+               fc->fe_sleep                = ops->sleep;
+               ops->sleep                  = flexcop_sleep;
+               return 1;
+       }
+       return 0;
+}
+#endif
+
+/* SkyStar2 DVB-S rev 2.6 */
+#if defined(CONFIG_DVB_STV0299_MODULE)
+static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
+       u32 srate, u32 ratio)
 {
        u8 aclk = 0;
        u8 bclk = 0;
 
-       if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
-       else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
-       else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
-       else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
-       else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
-       else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
-       stv0299_writereg (fe, 0x13, aclk);
-       stv0299_writereg (fe, 0x14, bclk);
-       stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
-       stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
-       stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
+       if (srate < 1500000) {
+               aclk = 0xb7; bclk = 0x47;
+       } else if (srate < 3000000) {
+               aclk = 0xb7; bclk = 0x4b;
+       } else if (srate < 7000000) {
+               aclk = 0xb7; bclk = 0x4f;
+       } else if (srate < 14000000) {
+               aclk = 0xb7; bclk = 0x53;
+       } else if (srate < 30000000) {
+               aclk = 0xb6; bclk = 0x53;
+       } else if (srate < 45000000) {
+               aclk = 0xb4; bclk = 0x51;
+       }
 
+       stv0299_writereg(fe, 0x13, aclk);
+       stv0299_writereg(fe, 0x14, bclk);
+       stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+       stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
+       stv0299_writereg(fe, 0x21,  ratio        & 0xf0);
        return 0;
 }
 
-static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
 {
        u8 buf[4];
        u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       struct i2c_msg msg = {
+       .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
        struct flexcop_device *fc = fe->dvb->priv;
-
        div = params->frequency / 125;
 
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
-       buf[2] = 0x84;  /* 0xC4 */
+       buf[2] = 0x84; /* 0xC4 */
        buf[3] = 0x08;
 
        if (params->frequency < 1500000)
@@ -203,48 +251,48 @@ static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dv
 }
 
 static u8 samsung_tbmu24112_inittab[] = {
-            0x01, 0x15,
-            0x02, 0x30,
-            0x03, 0x00,
-            0x04, 0x7D,
-            0x05, 0x35,
-            0x06, 0x02,
-            0x07, 0x00,
-            0x08, 0xC3,
-            0x0C, 0x00,
-            0x0D, 0x81,
-            0x0E, 0x23,
-            0x0F, 0x12,
-            0x10, 0x7E,
-            0x11, 0x84,
-            0x12, 0xB9,
-            0x13, 0x88,
-            0x14, 0x89,
-            0x15, 0xC9,
-            0x16, 0x00,
-            0x17, 0x5C,
-            0x18, 0x00,
-            0x19, 0x00,
-            0x1A, 0x00,
-            0x1C, 0x00,
-            0x1D, 0x00,
-            0x1E, 0x00,
-            0x1F, 0x3A,
-            0x20, 0x2E,
-            0x21, 0x80,
-            0x22, 0xFF,
-            0x23, 0xC1,
-            0x28, 0x00,
-            0x29, 0x1E,
-            0x2A, 0x14,
-            0x2B, 0x0F,
-            0x2C, 0x09,
-            0x2D, 0x05,
-            0x31, 0x1F,
-            0x32, 0x19,
-            0x33, 0xFE,
-            0x34, 0x93,
-            0xff, 0xff,
+       0x01, 0x15,
+       0x02, 0x30,
+       0x03, 0x00,
+       0x04, 0x7D,
+       0x05, 0x35,
+       0x06, 0x02,
+       0x07, 0x00,
+       0x08, 0xC3,
+       0x0C, 0x00,
+       0x0D, 0x81,
+       0x0E, 0x23,
+       0x0F, 0x12,
+       0x10, 0x7E,
+       0x11, 0x84,
+       0x12, 0xB9,
+       0x13, 0x88,
+       0x14, 0x89,
+       0x15, 0xC9,
+       0x16, 0x00,
+       0x17, 0x5C,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1A, 0x00,
+       0x1C, 0x00,
+       0x1D, 0x00,
+       0x1E, 0x00,
+       0x1F, 0x3A,
+       0x20, 0x2E,
+       0x21, 0x80,
+       0x22, 0xFF,
+       0x23, 0xC1,
+       0x28, 0x00,
+       0x29, 0x1E,
+       0x2A, 0x14,
+       0x2B, 0x0F,
+       0x2C, 0x09,
+       0x2D, 0x05,
+       0x31, 0x1F,
+       0x32, 0x19,
+       0x33, 0xFE,
+       0x34, 0x93,
+       0xff, 0xff,
 };
 
 static struct stv0299_config samsung_tbmu24112_config = {
@@ -259,27 +307,155 @@ static struct stv0299_config samsung_tbmu24112_config = {
        .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
 };
 
-/* dvb-t mt352 */
-static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
+static int skystar2_rev26_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
+       if (fc->fe != NULL) {
+               struct dvb_frontend_ops *ops  = &fc->fe->ops;
+               ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
+               ops->set_voltage = flexcop_set_voltage;
+               fc->fe_sleep = ops->sleep;
+               ops->sleep = flexcop_sleep;
+               return 1;
+       }
+       return 0;
+}
+#endif
+
+/* SkyStar2 DVB-S rev 2.7 */
+#if defined(CONFIG_DVB_S5H1420_MODULE)
+static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
+       .demod_address = 0x53,
+       .invert = 1,
+       .repeated_start_workaround = 1,
+       .serial_mpeg = 1,
+};
+
+static struct itd1000_config skystar2_rev2_7_itd1000_config = {
+       .i2c_address = 0x61,
+};
+
+static int skystar2_rev27_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       flexcop_ibi_value r108;
+       struct i2c_adapter *i2c_tuner;
+
+       /* enable no_base_addr - no repeated start when reading */
+       fc->fc_i2c_adap[0].no_base_addr = 1;
+       fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
+                           i2c);
+       if (!fc->fe)
+               goto fail;
+
+       i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
+       if (!i2c_tuner)
+               goto fail;
+
+       fc->fe_sleep = fc->fe->ops.sleep;
+       fc->fe->ops.sleep = flexcop_sleep;
+
+       /* enable no_base_addr - no repeated start when reading */
+       fc->fc_i2c_adap[2].no_base_addr = 1;
+       if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
+                       0x08, 1, 1)) {
+               err("ISL6421 could NOT be attached");
+               goto fail_isl;
+       }
+       info("ISL6421 successfully attached");
+
+       /* the ITD1000 requires a lower i2c clock - is it a problem ? */
+       r108.raw = 0x00000506;
+       fc->write_ibi_reg(fc, tw_sm_c_108, r108);
+       if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
+                       &skystar2_rev2_7_itd1000_config)) {
+               err("ITD1000 could NOT be attached");
+               /* Should i2c clock be restored? */
+               goto fail_isl;
+       }
+       info("ITD1000 successfully attached");
+
+       return 1;
+
+fail_isl:
+       fc->fc_i2c_adap[2].no_base_addr = 0;
+fail:
+       /* for the next devices we need it again */
+       fc->fc_i2c_adap[0].no_base_addr = 0;
+       return 0;
+}
+#endif
+
+/* SkyStar2 rev 2.8 */
+#if defined(CONFIG_DVB_CX24123_MODULE)
+static struct cx24123_config skystar2_rev2_8_cx24123_config = {
+       .demod_address = 0x55,
+       .dont_use_pll = 1,
+       .agc_callback = cx24113_agc_callback,
+};
+
+static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
+       .i2c_addr = 0x54,
+       .xtal_khz = 10111,
+};
+
+static int skystar2_rev28_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       struct i2c_adapter *i2c_tuner;
+
+       fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
+                           i2c);
+       if (!fc->fe)
+               return 0;
+
+       i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
+       if (!i2c_tuner)
+               return 0;
+
+       if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
+                       i2c_tuner)) {
+               err("CX24113 could NOT be attached");
+               return 0;
+       }
+       info("CX24113 successfully attached");
+
+       fc->fc_i2c_adap[2].no_base_addr = 1;
+       if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
+                       0x08, 0, 0)) {
+               err("ISL6421 could NOT be attached");
+               fc->fc_i2c_adap[2].no_base_addr = 0;
+               return 0;
+       }
+       info("ISL6421 successfully attached");
+       /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
+        * IR-receiver (PIC16F818) - but the card has no input for that ??? */
+       return 1;
+}
+#endif
+
+/* AirStar DVB-T */
+#if defined(CONFIG_DVB_MT352_MODULE)
+static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
 {
-       static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
-       static u8 mt352_reset [] = { 0x50, 0x80 };
-       static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-       static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
+       static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
+       static u8 mt352_reset[] = { 0x50, 0x80 };
+       static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+       static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
        static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
 
        mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
        udelay(2000);
        mt352_write(fe, mt352_reset, sizeof(mt352_reset));
        mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
        mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
        mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
        return 0;
 }
 
-static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
+static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
 {
        u32 div;
        unsigned char bs = 0;
@@ -287,19 +463,20 @@ static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_fro
        if (buf_len < 5)
                return -EINVAL;
 
-       #define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
        div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-       if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
-       if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
-       if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
+       if (params->frequency >= 48000000 && params->frequency <= 154000000) \
+               bs = 0x09;
+       if (params->frequency >= 161000000 && params->frequency <= 439000000) \
+               bs = 0x0a;
+       if (params->frequency >= 447000000 && params->frequency <= 863000000) \
+               bs = 0x08;
 
        pllbuf[0] = 0x61;
        pllbuf[1] = div >> 8;
        pllbuf[2] = div & 0xff;
        pllbuf[3] = 0xcc;
        pllbuf[4] = bs;
-
        return 5;
 }
 
@@ -308,70 +485,95 @@ static struct mt352_config samsung_tdtc9251dh0_config = {
        .demod_init    = samsung_tdtc9251dh0_demod_init,
 };
 
-static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+static int airstar_dvbt_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
+       if (fc->fe != NULL) {
+               fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
+               return 1;
+       }
+       return 0;
+}
+#endif
+
+/* AirStar ATSC 1st generation */
+#if defined(CONFIG_DVB_BCM3510_MODULE)
+static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
+       const struct firmware **fw, char* name)
 {
        struct flexcop_device *fc = fe->dvb->priv;
        return request_firmware(fw, name, fc->dev);
 }
 
-static struct lgdt330x_config air2pc_atsc_hd5000_config = {
-       .demod_address       = 0x59,
-       .demod_chip          = LGDT3303,
-       .serial_mpeg         = 0x04,
-       .clock_polarity_flip = 1,
-};
-
-static struct nxt200x_config samsung_tbmv_config = {
-       .demod_address    = 0x0a,
-};
-
 static struct bcm3510_config air2pc_atsc_first_gen_config = {
        .demod_address    = 0x0f,
        .request_firmware = flexcop_fe_request_firmware,
 };
 
-static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int airstar_atsc1_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
 {
-       u8 buf[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-       struct flexcop_device *fc = fe->dvb->priv;
-
-       div = (params->frequency + (125/2)) / 125;
+       fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
+       return fc->fe != NULL;
+}
+#endif
 
-       buf[0] = (div >> 8) & 0x7f;
-       buf[1] = (div >> 0) & 0xff;
-       buf[2] = 0x84 | ((div >> 10) & 0x60);
-       buf[3] = 0x80;
+/* AirStar ATSC 2nd generation */
+#if defined(CONFIG_DVB_NXT200X_MODULE)
+static struct nxt200x_config samsung_tbmv_config = {
+       .demod_address = 0x0a,
+};
 
-       if (params->frequency < 1550000)
-               buf[3] |= 0x02;
+static int airstar_atsc2_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
+       if (!fc->fe)
+               return 0;
 
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
-               return -EIO;
-       return 0;
+       return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
+                           DVB_PLL_SAMSUNG_TBMV);
 }
+#endif
 
-static struct mt312_config skystar23_samsung_tbdu18132_config = {
-
-       .demod_address = 0x0e,
+/* AirStar ATSC 3rd generation */
+#if defined(CONFIG_DVB_LGDT330X_MODULE)
+static struct lgdt330x_config air2pc_atsc_hd5000_config = {
+       .demod_address       = 0x59,
+       .demod_chip          = LGDT3303,
+       .serial_mpeg         = 0x04,
+       .clock_polarity_flip = 1,
 };
 
+static int airstar_atsc3_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
+       if (!fc->fe)
+               return 0;
+
+       return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
+                           TUNER_LG_TDVS_H06XF);
+}
+#endif
+
+/* CableStar2 DVB-C */
+#if defined(CONFIG_DVB_STV0297_MODULE)
 static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
-                                              struct dvb_frontend_parameters *fep)
+               struct dvb_frontend_parameters *fep)
 {
        struct flexcop_device *fc = fe->dvb->priv;
        u8 buf[4];
        u16 div;
        int ret;
 
-/*  62.5 kHz * 10 */
+/* 62.5 kHz * 10 */
 #define REF_FREQ    625
 #define FREQ_OFFSET 36125
 
-       div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10)  / REF_FREQ; // 4 MHz = 4000 KHz
+       div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
+/* 4 MHz = 4000 KHz */
 
        buf[0] = (u8)( div >> 8) & 0x7f;
        buf[1] = (u8)        div & 0xff;
@@ -384,11 +586,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
  * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
        buf[2] = 0x95;
 
-// Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
-//  47 - 153   0  *  0   0   0   0   0   1   0x01
-// 153 - 430   0  *  0   0   0   0   1   0   0x02
-// 430 - 822   0  *  0   0   1   0   0   0   0x08
-// 822 - 862   1  *  0   0   1   0   0   0   0x88
+/* Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
+ *  47 - 153   0  *  0   0   0   0   0   1   0x01
+ * 153 - 430   0  *  0   0   0   0   1   0   0x02
+ * 430 - 822   0  *  0   0   1   0   0   0   0x08
+ * 822 - 862   1  *  0   0   1   0   0   0   0x88 */
 
             if (fep->frequency <= 153000000) buf[3] = 0x01;
        else if (fep->frequency <= 430000000) buf[3] = 0x02;
@@ -397,11 +599,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
-       deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
+       deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
+       buf[0], buf[1], buf[2], buf[3]);
        ret = fc->i2c_request(&fc->fc_i2c_adap[2],
-               FC_WRITE, 0x61, buf[0], &buf[1], 3);
+                       FC_WRITE, 0x61, buf[0], &buf[1], 3);
        deb_tuner("tuner write returned: %d\n",ret);
-
        return ret;
 }
 
@@ -481,182 +683,73 @@ static u8 alps_tdee4_stv0297_inittab[] = {
 static struct stv0297_config alps_tdee4_stv0297_config = {
        .demod_address = 0x1c,
        .inittab = alps_tdee4_stv0297_inittab,
-//     .invert = 1,
-//     .pll_set = alps_tdee4_stv0297_pll_set,
-};
-
-
-/* SkyStar2 rev2.7 (a/u) */
-static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
-       .demod_address = 0x53,
-       .invert = 1,
-       .repeated_start_workaround = 1,
-       .serial_mpeg = 1,
-};
-
-static struct itd1000_config skystar2_rev2_7_itd1000_config = {
-       .i2c_address = 0x61,
 };
 
-/* SkyStar2 rev2.8 */
-static struct cx24123_config skystar2_rev2_8_cx24123_config = {
-       .demod_address = 0x55,
-       .dont_use_pll = 1,
-       .agc_callback = cx24113_agc_callback,
-};
-
-static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
-       .i2c_addr = 0x54,
-       .xtal_khz = 10111,
-};
-
-/* try to figure out the frontend, each card/box can have on of the following list */
-int flexcop_frontend_init(struct flexcop_device *fc)
+static int cablestar2_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
 {
-       struct dvb_frontend_ops *ops;
-       struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap;
-       struct i2c_adapter *i2c_tuner;
-
-       /* enable no_base_addr - no repeated start when reading */
-       fc->fc_i2c_adap[0].no_base_addr = 1;
-       fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, i2c);
-       if (fc->fe != NULL) {
-               flexcop_ibi_value r108;
-               i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
-               ops = &fc->fe->ops;
-
-               fc->fe_sleep = ops->sleep;
-               ops->sleep   = flexcop_sleep;
-
-               fc->dev_type = FC_SKY_REV27;
-
-               /* enable no_base_addr - no repeated start when reading */
-               fc->fc_i2c_adap[2].no_base_addr = 1;
-               if (dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL)
-                       err("ISL6421 could NOT be attached");
-               else
-                       info("ISL6421 successfully attached");
-
-               /* the ITD1000 requires a lower i2c clock - it slows down the stuff for everyone - but is it a problem ? */
-               r108.raw = 0x00000506;
-               fc->write_ibi_reg(fc, tw_sm_c_108, r108);
-               if (i2c_tuner) {
-                       if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config) == NULL)
-                               err("ITD1000 could NOT be attached");
-                       else
-                               info("ITD1000 successfully attached");
-               }
-               goto fe_found;
-       }
-       fc->fc_i2c_adap[0].no_base_addr = 0; /* for the next devices we need it again */
-
-       /* try the sky v2.8 (cx24123, isl6421) */
-       fc->fe = dvb_attach(cx24123_attach,
-               &skystar2_rev2_8_cx24123_config, i2c);
-       if (fc->fe != NULL) {
-               i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
-               if (i2c_tuner != NULL) {
-                       if (dvb_attach(cx24113_attach, fc->fe,
-                                       &skystar2_rev2_8_cx24113_config,
-                                       i2c_tuner) == NULL)
-                               err("CX24113 could NOT be attached");
-                       else
-                               info("CX24113 successfully attached");
-               }
-
-               fc->dev_type = FC_SKY_REV28;
-
-               fc->fc_i2c_adap[2].no_base_addr = 1;
-               if (dvb_attach(isl6421_attach, fc->fe,
-                      &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL)
-                       err("ISL6421 could NOT be attached");
-               else
-                       info("ISL6421 successfully attached");
-
-               /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
-                * IR-receiver (PIC16F818) - but the card has no input for
-                * that ??? */
-
-               goto fe_found;
-    }
-
-       /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
-       fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
-       if (fc->fe != NULL) {
-               ops = &fc->fe->ops;
-
-               ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
-
-               ops->set_voltage = flexcop_set_voltage;
-
-               fc->fe_sleep = ops->sleep;
-               ops->sleep = flexcop_sleep;
-
-               fc->dev_type = FC_SKY_REV26;
-               goto fe_found;
-       }
-
-       /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
-       fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_AIR_DVBT;
-               fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
-               goto fe_found;
-       }
-
-       /* try the air atsc 2nd generation (nxt2002) */
-       fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_AIR_ATSC2;
-               dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
-               goto fe_found;
-       }
-
-       fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_AIR_ATSC3;
-               dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
-                               TUNER_LG_TDVS_H06XF);
-               goto fe_found;
-       }
-
-       /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
-       fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_AIR_ATSC1;
-               goto fe_found;
-       }
-
-       /* try the cable dvb (stv0297) */
        fc->fc_i2c_adap[0].no_base_addr = 1;
        fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_CABLE;
-               fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
-               goto fe_found;
+       if (!fc->fe) {
+               /* Reset for next frontend to try */
+               fc->fc_i2c_adap[0].no_base_addr = 0;
+               return 0;
        }
-       fc->fc_i2c_adap[0].no_base_addr = 0;
-
-       /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
-       fc->fe = dvb_attach(mt312_attach,
-               &skystar23_samsung_tbdu18132_config, i2c);
-       if (fc->fe != NULL) {
-               ops = &fc->fe->ops;
-
-               ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
-
-               ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
-               ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
-               ops->set_tone               = flexcop_set_tone;
-               ops->set_voltage            = flexcop_set_voltage;
-
-               fc->fe_sleep                = ops->sleep;
-               ops->sleep                  = flexcop_sleep;
+       fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
+       return 1;
+}
+#endif
+
+static struct {
+       flexcop_device_type_t type;
+       int (*attach)(struct flexcop_device *, struct i2c_adapter *);
+} flexcop_frontends[] = {
+#if defined(CONFIG_DVB_S5H1420_MODULE)
+       { FC_SKY_REV27, skystar2_rev27_attach },
+#endif
+#if defined(CONFIG_DVB_CX24123_MODULE)
+       { FC_SKY_REV28, skystar2_rev28_attach },
+#endif
+#if defined(CONFIG_DVB_STV0299_MODULE)
+       { FC_SKY_REV26, skystar2_rev26_attach },
+#endif
+#if defined(CONFIG_DVB_MT352_MODULE)
+       { FC_AIR_DVBT, airstar_dvbt_attach },
+#endif
+#if defined(CONFIG_DVB_NXT200X_MODULE)
+       { FC_AIR_ATSC2, airstar_atsc2_attach },
+#endif
+#if defined(CONFIG_DVB_LGDT330X_MODULE)
+       { FC_AIR_ATSC3, airstar_atsc3_attach },
+#endif
+#if defined(CONFIG_DVB_BCM3510_MODULE)
+       { FC_AIR_ATSC1, airstar_atsc1_attach },
+#endif
+#if defined(CONFIG_DVB_STV0297_MODULE)
+       { FC_CABLE, cablestar2_attach },
+#endif
+#if defined(CONFIG_DVB_MT312_MODULE)
+       { FC_SKY_REV23, skystar2_rev23_attach },
+#endif
+};
 
-               fc->dev_type                = FC_SKY_REV23;
-               goto fe_found;
+/* try to figure out the frontend */
+int flexcop_frontend_init(struct flexcop_device *fc)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
+               /* type needs to be set before, because of some workarounds
+                * done based on the probed card type */
+               fc->dev_type = flexcop_frontends[i].type;
+               if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
+                       goto fe_found;
+               /* Clean up partially attached frontend */
+               if (fc->fe) {
+                       dvb_frontend_detach(fc->fe);
+                       fc->fe = NULL;
+               }
        }
-
+       fc->dev_type = FC_UNK;
        err("no frontend driver found for this B2C2/FlexCop adapter");
        return -ENODEV;
 
@@ -664,9 +757,7 @@ fe_found:
        info("found '%s' .", fc->fe->ops.info.name);
        if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
                err("frontend registration failed!");
-               ops = &fc->fe->ops;
-               if (ops->release != NULL)
-                       ops->release(fc->fe);
+               dvb_frontend_detach(fc->fe);
                fc->fe = NULL;
                return -EINVAL;
        }
@@ -680,6 +771,5 @@ void flexcop_frontend_exit(struct flexcop_device *fc)
                dvb_unregister_frontend(fc->fe);
                dvb_frontend_detach(fc->fe);
        }
-
        fc->init_state &= ~FC_STATE_FE_INIT;
 }
index e2bed5076485635b7338fbde2b3f3e1f9aeb0f7b..fd1df2352764d4efa7296aeaeaf81d385512d4f4 100644 (file)
@@ -200,7 +200,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
                                        msgs[i].buf[0], &msgs[i].buf[1],
                                        msgs[i].len - 1);
                if (ret < 0) {
-                       err("i2c master_xfer failed");
+                       deb_i2c("i2c master_xfer failed");
                        break;
                }
        }
index e56627d2f0f42ddeaafdd38a5730fce0b192e527..f06f3a9070f564ca13e7c6bd28254b7891d4f6bf 100644 (file)
@@ -46,16 +46,16 @@ static const char *flexcop_revision_names[] = {
 };
 
 static const char *flexcop_device_names[] = {
-       "Unknown device",
-       "Air2PC/AirStar 2 DVB-T",
-       "Air2PC/AirStar 2 ATSC 1st generation",
-       "Air2PC/AirStar 2 ATSC 2nd generation",
-       "Sky2PC/SkyStar 2 DVB-S",
-       "Sky2PC/SkyStar 2 DVB-S (old version)",
-       "Cable2PC/CableStar 2 DVB-C",
-       "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
-       "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
-       "Sky2PC/SkyStar 2 DVB-S rev 2.8",
+       [FC_UNK]        = "Unknown device",
+       [FC_CABLE]      = "Cable2PC/CableStar 2 DVB-C",
+       [FC_AIR_DVBT]   = "Air2PC/AirStar 2 DVB-T",
+       [FC_AIR_ATSC1]  = "Air2PC/AirStar 2 ATSC 1st generation",
+       [FC_AIR_ATSC2]  = "Air2PC/AirStar 2 ATSC 2nd generation",
+       [FC_AIR_ATSC3]  = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
+       [FC_SKY_REV23]  = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
+       [FC_SKY_REV26]  = "Sky2PC/SkyStar 2 DVB-S rev 2.6",
+       [FC_SKY_REV27]  = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
+       [FC_SKY_REV28]  = "Sky2PC/SkyStar 2 DVB-S rev 2.8",
 };
 
 static const char *flexcop_bus_names[] = {
index 56d8fab688bb91f4ca1c404ed86aeacbefbaa411..a24c125331f0adbed30e1f9a289661483741f57b 100644 (file)
@@ -508,12 +508,6 @@ static int __devinit bt878_probe(struct pci_dev *dev,
        pci_set_master(dev);
        pci_set_drvdata(dev, bt);
 
-/*        if(init_bt878(btv) < 0) {
-               bt878_remove(dev);
-               return -EIO;
-       }
-*/
-
        if ((result = bt878_mem_alloc(bt))) {
                printk(KERN_ERR "bt878: failed to allocate memory!\n");
                goto fail2;
@@ -579,7 +573,7 @@ static struct pci_driver bt878_pci_driver = {
       .name    = "bt878",
       .id_table = bt878_pci_tbl,
       .probe   = bt878_probe,
-      .remove  = bt878_remove,
+      .remove  = __devexit_p(bt878_remove),
 };
 
 static int bt878_pci_driver_registered;
index 971a8b18f6dd7214a9b797697e09baf386ff7ed8..4dbd7d4185af2dba90dd610c62e49f1738cdda1d 100644 (file)
@@ -51,6 +51,9 @@
 #ifndef PCI_VENDOR_ID_TRIGEM
 #define PCI_VENDOR_ID_TRIGEM   0x109f
 #endif
+#ifndef PCI_VENDOR_ID_AXESS
+#define PCI_VENDOR_ID_AXESS    0x195d
+#endif
 #ifndef PCI_DEVICE_ID_DM1105
 #define PCI_DEVICE_ID_DM1105   0x036f
 #endif
@@ -60,6 +63,9 @@
 #ifndef PCI_DEVICE_ID_DW2004
 #define PCI_DEVICE_ID_DW2004   0x2004
 #endif
+#ifndef PCI_DEVICE_ID_DM05
+#define PCI_DEVICE_ID_DM05     0x1105
+#endif
 /* ----------------------------------------------- */
 /* sdmc dm1105 registers */
 
 #define DM1105_LNB_13V                         0x00010100
 #define DM1105_LNB_18V                         0x00000100
 
+/* GPIO's for LNB power control for Axess DM05 */
+#define DM05_LNB_MASK                          0x00000000
+#define DM05_LNB_13V                           0x00020000
+#define DM05_LNB_18V                           0x00030000
+
 static int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
@@ -188,6 +199,8 @@ struct dm1105dvb {
 
        /* irq */
        struct work_struct work;
+       struct workqueue_struct *wq;
+       char wqn[16];
 
        /* dma */
        dma_addr_t dma_addr;
@@ -313,15 +326,25 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
 static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
+       u32 lnb_mask, lnb_13v, lnb_18v;
 
-               if (voltage == SEC_VOLTAGE_18) {
-                       outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
-                       outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL));
-               } else  {
-               /*LNB ON-13V by default!*/
-                       outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
-                       outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL));
-               }
+       switch (dm1105dvb->pdev->subsystem_device) {
+       case PCI_DEVICE_ID_DM05:
+               lnb_mask = DM05_LNB_MASK;
+               lnb_13v = DM05_LNB_13V;
+               lnb_18v = DM05_LNB_18V;
+               break;
+       default:
+               lnb_mask = DM1105_LNB_MASK;
+               lnb_13v = DM1105_LNB_13V;
+               lnb_18v = DM1105_LNB_18V;
+       }
+
+       outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
+       if (voltage == SEC_VOLTAGE_18)
+               outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
+       else
+               outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
 
        return 0;
 }
@@ -440,7 +463,7 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
        case (INTSTS_TSIRQ | INTSTS_IR):
                dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
                                        inl(dm_io_mem(DM1105_STADR));
-               schedule_work(&dm1105dvb->work);
+               queue_work(dm1105dvb->wq, &dm1105dvb->work);
                break;
        case INTSTS_IR:
                dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
@@ -567,46 +590,44 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
        int ret;
 
        switch (dm1105dvb->pdev->subsystem_device) {
-       case PCI_DEVICE_ID_DW2002:
+       case PCI_DEVICE_ID_DW2004:
                dm1105dvb->fe = dvb_attach(
-                       stv0299_attach, &sharp_z0194a_config,
+                       cx24116_attach, &serit_sp2633_config,
                        &dm1105dvb->i2c_adap);
+               if (dm1105dvb->fe)
+                       dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
 
+               break;
+       default:
+               dm1105dvb->fe = dvb_attach(
+                       stv0299_attach, &sharp_z0194a_config,
+                       &dm1105dvb->i2c_adap);
                if (dm1105dvb->fe) {
                        dm1105dvb->fe->ops.set_voltage =
                                                        dm1105dvb_set_voltage;
                        dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
                                        &dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
+                       break;
                }
 
-               if (!dm1105dvb->fe) {
-                       dm1105dvb->fe = dvb_attach(
-                               stv0288_attach, &earda_config,
-                               &dm1105dvb->i2c_adap);
-                       if (dm1105dvb->fe) {
-                               dm1105dvb->fe->ops.set_voltage =
-                                                       dm1105dvb_set_voltage;
-                               dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
-                                               &dm1105dvb->i2c_adap);
-                       }
+               dm1105dvb->fe = dvb_attach(
+                       stv0288_attach, &earda_config,
+                       &dm1105dvb->i2c_adap);
+               if (dm1105dvb->fe) {
+                       dm1105dvb->fe->ops.set_voltage =
+                                               dm1105dvb_set_voltage;
+                       dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
+                                       &dm1105dvb->i2c_adap);
+                       break;
                }
 
-               if (!dm1105dvb->fe) {
-                       dm1105dvb->fe = dvb_attach(
-                               si21xx_attach, &serit_config,
-                               &dm1105dvb->i2c_adap);
-                       if (dm1105dvb->fe)
-                               dm1105dvb->fe->ops.set_voltage =
-                                                       dm1105dvb_set_voltage;
-               }
-               break;
-       case PCI_DEVICE_ID_DW2004:
                dm1105dvb->fe = dvb_attach(
-                       cx24116_attach, &serit_sp2633_config,
+                       si21xx_attach, &serit_config,
                        &dm1105dvb->i2c_adap);
                if (dm1105dvb->fe)
-                       dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
-               break;
+                       dm1105dvb->fe->ops.set_voltage =
+                                               dm1105dvb_set_voltage;
+
        }
 
        if (!dm1105dvb->fe) {
@@ -630,10 +651,17 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
        static u8 command[1] = { 0x28 };
 
        struct i2c_msg msg[] = {
-               { .addr = IIC_24C01_addr >> 1, .flags = 0,
-                               .buf = command, .len = 1 },
-               { .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD,
-                               .buf = mac, .len = 6 },
+               {
+                       .addr = IIC_24C01_addr >> 1,
+                       .flags = 0,
+                       .buf = command,
+                       .len = 1
+               }, {
+                       .addr = IIC_24C01_addr >> 1,
+                       .flags = I2C_M_RD,
+                       .buf = mac,
+                       .len = 6
+               },
        };
 
        dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
@@ -752,14 +780,22 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
        dm1105_ir_init(dm1105dvb);
 
        INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
+       sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
+       dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn);
+       if (!dm1105dvb->wq)
+               goto err_dvb_net;
 
        ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
                                                DRIVER_NAME, dm1105dvb);
        if (ret < 0)
-               goto err_free_irq;
+               goto err_workqueue;
 
        return 0;
 
+err_workqueue:
+       destroy_workqueue(dm1105dvb->wq);
+err_dvb_net:
+       dvb_net_release(&dm1105dvb->dvbnet);
 err_disconnect_frontend:
        dmx->disconnect_frontend(dmx);
 err_remove_mem_frontend:
@@ -776,8 +812,6 @@ err_i2c_del_adapter:
        i2c_del_adapter(&dm1105dvb->i2c_adap);
 err_dm1105dvb_hw_exit:
        dm1105dvb_hw_exit(dm1105dvb);
-err_free_irq:
-       free_irq(pdev->irq, dm1105dvb);
 err_pci_iounmap:
        pci_iounmap(pdev, dm1105dvb->io_mem);
 err_pci_release_regions:
@@ -833,6 +867,11 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = {
                .device = PCI_DEVICE_ID_DM1105,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_DEVICE_ID_DW2004,
+       }, {
+               .vendor = PCI_VENDOR_ID_AXESS,
+               .device = PCI_DEVICE_ID_DM05,
+               .subvendor = PCI_VENDOR_ID_AXESS,
+               .subdevice = PCI_DEVICE_ID_DM05,
        }, {
                /* empty */
        },
index c35fbb8d8f4a1b5c8c07cda277ad23f76cb558ab..6d6121eb5d592ea9157f0a8610069abc8ab4d8c9 100644 (file)
@@ -244,19 +244,13 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
-       int ret;
 
-       if (dmxdev->exit) {
-               mutex_unlock(&dmxdev->mutex);
+       if (dmxdev->exit)
                return -ENODEV;
-       }
 
-       //mutex_lock(&dmxdev->mutex);
-       ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
-                                    file->f_flags & O_NONBLOCK,
-                                    buf, count, ppos);
-       //mutex_unlock(&dmxdev->mutex);
-       return ret;
+       return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+                                     file->f_flags & O_NONBLOCK,
+                                     buf, count, ppos);
 }
 
 static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
index e2eca0b1fe7cfad6dc1215aa6d2bd1247497b93e..cfe2768d24af58133ecd47ba8461e25aa062d12b 100644 (file)
 */
 // #define DVB_DEMUX_SECTION_LOSS_LOG
 
+static int dvb_demux_tscheck;
+module_param(dvb_demux_tscheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_tscheck,
+               "enable transport stream continuity and TEI check");
+
+#define dprintk_tscheck(x...) do {                              \
+               if (dvb_demux_tscheck && printk_ratelimit())    \
+                       printk(x);                              \
+       } while (0)
+
 /******************************************************************************
  * static inlined helper functions
  ******************************************************************************/
@@ -376,6 +386,36 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
        u16 pid = ts_pid(buf);
        int dvr_done = 0;
 
+       if (dvb_demux_tscheck) {
+               if (!demux->cnt_storage)
+                       demux->cnt_storage = vmalloc(MAX_PID + 1);
+
+               if (!demux->cnt_storage) {
+                       printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
+                       dvb_demux_tscheck = 0;
+                       goto no_dvb_demux_tscheck;
+               }
+
+               /* check pkt counter */
+               if (pid < MAX_PID) {
+                       if (buf[1] & 0x80)
+                               dprintk_tscheck("TEI detected. "
+                                               "PID=0x%x data1=0x%x\n",
+                                               pid, buf[1]);
+
+                       if ((buf[3] & 0xf) != demux->cnt_storage[pid])
+                               dprintk_tscheck("TS packet counter mismatch. "
+                                               "PID=0x%x expected 0x%x "
+                                               "got 0x%x\n",
+                                               pid, demux->cnt_storage[pid],
+                                               buf[3] & 0xf);
+
+                       demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
+               };
+               /* end check */
+       };
+no_dvb_demux_tscheck:
+
        list_for_each_entry(feed, &demux->feed_list, list_head) {
                if ((feed->pid != pid) && (feed->pid != 0x2000))
                        continue;
@@ -1160,6 +1200,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
        int i;
        struct dmx_demux *dmx = &dvbdemux->dmx;
 
+       dvbdemux->cnt_storage = NULL;
        dvbdemux->users = 0;
        dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
 
@@ -1226,6 +1267,7 @@ EXPORT_SYMBOL(dvb_dmx_init);
 
 void dvb_dmx_release(struct dvb_demux *dvbdemux)
 {
+       vfree(dvbdemux->cnt_storage);
        vfree(dvbdemux->filter);
        vfree(dvbdemux->feed);
 }
index 2c5f915329ca9c5658e68628208f57c58c856364..2fe05d03240d75ca8f6631772f4c8a3baf9aaf5a 100644 (file)
@@ -42,6 +42,8 @@
 
 #define DVB_DEMUX_MASK_MAX 18
 
+#define MAX_PID 0x1fff
+
 struct dvb_demux_filter {
        struct dmx_section_filter filter;
        u8 maskandmode[DMX_MAX_FILTER_SIZE];
@@ -127,6 +129,8 @@ struct dvb_demux {
 
        struct mutex mutex;
        spinlock_t lock;
+
+       uint8_t *cnt_storage; /* for TS continuity check */
 };
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);
index ebc78157b9b8ced38cf637b9c336a0009f868836..f50ca7292a7d4e8bd6c69ffd58368db0c749b923 100644 (file)
@@ -543,6 +543,7 @@ restart:
 
                if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
                        /* got signal or quitting */
+                       fepriv->exit = 1;
                        break;
                }
 
@@ -656,6 +657,7 @@ restart:
        }
 
        fepriv->thread = NULL;
+       fepriv->exit = 0;
        mb();
 
        dvb_frontend_wakeup(fe);
index 1bb66e1ed5a7d7a267b023d86ca0490b28bb7beb..496c1a37034ced8d9ab89aaff3cd2ef30c024b08 100644 (file)
@@ -261,6 +261,7 @@ config DVB_USB_DW2102
        select DVB_STB6000 if !DVB_FE_CUSTOMISE
        select DVB_CX24116 if !DVB_FE_CUSTOMISE
        select DVB_SI21XX if !DVB_FE_CUSTOMISE
+       select DVB_TDA10021 if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
          and the TeVii S650.
index 53bfc8e42fb940f9651d0e66e16efc7fe57fa8d3..4cb31e7c13c2856be433e2feb3feee225d02db64 100644 (file)
@@ -40,7 +40,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 static DEFINE_MUTEX(af9015_usb_mutex);
 
 static struct af9015_config af9015_config;
-static struct dvb_usb_device_properties af9015_properties[2];
+static struct dvb_usb_device_properties af9015_properties[3];
 static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
 
 static struct af9013_config af9015_af9013_config[] = {
@@ -538,7 +538,7 @@ exit:
 /* dump eeprom */
 static int af9015_eeprom_dump(struct dvb_usb_device *d)
 {
-       char buf[52], buf2[4];
+       char buf[4+3*16+1], buf2[4];
        u8 reg, val;
 
        for (reg = 0; ; reg++) {
@@ -1261,7 +1261,11 @@ static struct usb_device_id af9015_usb_table[] = {
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_2)},
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_3)},
        {USB_DEVICE(USB_VID_AFATECH,   USB_PID_TREKSTOR_DVBT)},
-       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
+/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
+       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_CONCEPTRONIC_CTVDIGRCU)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_MC810)},
+       {USB_DEVICE(USB_VID_KYE,       USB_PID_GENIUS_TVGO_DVB_T03)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1321,7 +1325,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 9,
+               .num_device_descs = 9, /* max 9 */
                .devices = {
                        {
                                .name = "Afatech AF9015 DVB-T USB2.0 stick",
@@ -1426,7 +1430,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 9,
+               .num_device_descs = 9, /* max 9 */
                .devices = {
                        {
                                .name = "Xtensions XD-380",
@@ -1478,7 +1482,85 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                .warm_ids = {NULL},
                        },
                }
-       }
+       }, {
+               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+               .usb_ctrl = DEVICE_SPECIFIC,
+               .download_firmware = af9015_download_firmware,
+               .firmware = "dvb-usb-af9015.fw",
+               .no_reconnect = 1,
+
+               .size_of_priv = sizeof(struct af9015_state), \
+
+               .num_adapters = 2,
+               .adapter = {
+                       {
+                               .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+                               .pid_filter_count = 32,
+                               .pid_filter       = af9015_pid_filter,
+                               .pid_filter_ctrl  = af9015_pid_filter_ctrl,
+
+                               .frontend_attach =
+                                       af9015_af9013_frontend_attach,
+                               .tuner_attach    = af9015_tuner_attach,
+                               .stream = {
+                                       .type = USB_BULK,
+                                       .count = 6,
+                                       .endpoint = 0x84,
+                               },
+                       },
+                       {
+                               .frontend_attach =
+                                       af9015_af9013_frontend_attach,
+                               .tuner_attach    = af9015_tuner_attach,
+                               .stream = {
+                                       .type = USB_BULK,
+                                       .count = 6,
+                                       .endpoint = 0x85,
+                                       .u = {
+                                               .bulk = {
+                                                       .buffersize =
+                                               TS_USB20_MAX_PACKET_SIZE,
+                                               }
+                                       }
+                               },
+                       }
+               },
+
+               .identify_state = af9015_identify_state,
+
+               .rc_query         = af9015_rc_query,
+               .rc_interval      = 150,
+
+               .i2c_algo = &af9015_i2c_algo,
+
+               .num_device_descs = 4, /* max 9 */
+               .devices = {
+                       {
+                               .name = "AverMedia AVerTV Volar GPS 805 (A805)",
+                               .cold_ids = {&af9015_usb_table[21], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
+                                       "V3.0",
+                               .cold_ids = {&af9015_usb_table[22], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "KWorld Digial MC-810",
+                               .cold_ids = {&af9015_usb_table[23], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "Genius TVGo DVB-T03",
+                               .cold_ids = {&af9015_usb_table[24], NULL},
+                               .warm_ids = {NULL},
+                       },
+               }
+       },
 };
 
 static int af9015_usb_probe(struct usb_interface *intf,
index 8ddbadf62194c4733046c3d0e39c702f75c3acb6..818b2ab584bf927bd00d0e1e369a24c94f2b9bca 100644 (file)
@@ -1346,9 +1346,9 @@ static int dib0700_xc5000_tuner_callback(void *priv, int component,
        if (command == XC5000_TUNER_RESET) {
                /* Reset the tuner */
                dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
-               msleep(330); /* from Windows USB trace */
+               msleep(10);
                dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
-               msleep(330); /* from Windows USB trace */
+               msleep(10);
        } else {
                err("xc5000: unknown tuner callback command: %d\n", command);
                return -EINVAL;
@@ -1493,6 +1493,10 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) },
        { USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_MC770) },
        { USB_DEVICE(USB_VID_ELGATO,    USB_PID_ELGATO_EYETV_DTT) },
+/* 50 */{ USB_DEVICE(USB_VID_ELGATO,   USB_PID_ELGATO_EYETV_DTT_Dlx) },
+       { USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_H) },
+       { USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_T3) },
+       { USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_T5) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1692,7 +1696,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 11,
+               .num_device_descs = 12,
                .devices = {
                        {   "DiBcom STK7070P reference design",
                                { &dib0700_usb_id_table[15], NULL },
@@ -1726,8 +1730,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[30], NULL },
                                { NULL },
                        },
-                       {   "Terratec Cinergy T USB XXS",
-                               { &dib0700_usb_id_table[33], NULL },
+                       {   "Terratec Cinergy T USB XXS/ T3",
+                               { &dib0700_usb_id_table[33],
+                                       &dib0700_usb_id_table[52], NULL },
                                { NULL },
                        },
                        {   "Elgato EyeTV DTT",
@@ -1738,6 +1743,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[45], NULL },
                                { NULL },
                        },
+                       {   "Elgato EyeTV Dtt Dlx PD378S",
+                               { &dib0700_usb_id_table[50], NULL },
+                               { NULL },
+                       },
                },
 
                .rc_interval      = DEFAULT_RC_INTERVAL,
@@ -1784,8 +1793,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[36], NULL },
                                { NULL },
                        },
-                       {  "Terratec Cinergy DT USB XS Diversity",
-                               { &dib0700_usb_id_table[43], NULL },
+                       {  "Terratec Cinergy DT USB XS Diversity/ T5",
+                               { &dib0700_usb_id_table[43],
+                                       &dib0700_usb_id_table[53], NULL},
                                { NULL },
                        },
                        {  "Sony PlayTV",
@@ -1812,7 +1822,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 7,
+               .num_device_descs = 8,
                .devices = {
                        {   "Terratec Cinergy HT USB XE",
                                { &dib0700_usb_id_table[27], NULL },
@@ -1842,6 +1852,11 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[48], NULL },
                                { NULL },
                        },
+                       {   "Leadtek WinFast DTV Dongle H",
+                               { &dib0700_usb_id_table[51], NULL },
+                               { NULL },
+                       },
+
                },
                .rc_interval      = DEFAULT_RC_INTERVAL,
                .rc_key_map       = dib0700_rc_keys,
index 8ee6cd4da9e7c1053099792ef5ec0700bbd29ccf..8dbad1ec53c404782d16c33e8929976a3ad8e386 100644 (file)
@@ -133,14 +133,17 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
 
        for (i = 0; i < num; i++) {
                /* write/read request */
-               if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+               if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
+                                         && (msg[i+1].flags & I2C_M_RD)) {
                        if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
                                                msg[i+1].buf,msg[i+1].len) < 0)
                                break;
                        i++;
-               } else
+               } else if ((msg[i].flags & I2C_M_RD) == 0) {
                        if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
                                break;
+               } else
+                       break;
        }
 
        mutex_unlock(&d->i2c_mutex);
index f506c74119f3bfb48d5714d2f3ad6d36e11d3066..9593b72899946c3e3f95f97e6cad7ebe191459b6 100644 (file)
@@ -80,6 +80,7 @@
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM               0x010d
 #define USB_PID_COMPRO_VIDEOMATE_U500                  0x1e78
 #define USB_PID_COMPRO_VIDEOMATE_U500_PC               0x1e80
+#define USB_PID_CONCEPTRONIC_CTVDIGRCU                 0xe397
 #define USB_PID_CONEXANT_D680_DMB                      0x86d6
 #define USB_PID_DIBCOM_HOOK_DEFAULT                    0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM             0x0065
@@ -97,6 +98,7 @@
 #define USB_PID_DPOSH_M9206_COLD                       0x9206
 #define USB_PID_DPOSH_M9206_WARM                       0xa090
 #define USB_PID_UNIWILL_STK7700P                       0x6003
+#define USB_PID_GENIUS_TVGO_DVB_T03                    0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
 #define USB_PID_INTEL_CE9500                           0x9500
 #define USB_PID_KWORLD_395U                            0xe396
 #define USB_PID_KWORLD_395U_2                          0xe39b
 #define USB_PID_KWORLD_395U_3                          0xe395
+#define USB_PID_KWORLD_MC810                           0xc810
 #define USB_PID_KWORLD_PC160_2T                                0xc160
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
 #define USB_PID_AVERMEDIA_A309                         0xa309
 #define USB_PID_AVERMEDIA_A310                         0xa310
 #define USB_PID_AVERMEDIA_A850                         0x850a
+#define USB_PID_AVERMEDIA_A805                         0xa805
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY       0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2     0x0081
 #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS            0x0060
 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS             0x0062
 #define USB_PID_TERRATEC_CINERGY_T_XXS                 0x0078
+#define USB_PID_TERRATEC_T3                            0x10a0
+#define USB_PID_TERRATEC_T5                            0x10a1
 #define USB_PID_PINNACLE_EXPRESSCARD_320CX             0x022e
 #define USB_PID_PINNACLE_PCTV2000E                     0x022c
 #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH              0x0228
 #define USB_PID_WINFAST_DTV_DONGLE_COLD                        0x6025
 #define USB_PID_WINFAST_DTV_DONGLE_WARM                        0x6026
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P            0x6f00
+#define USB_PID_WINFAST_DTV_DONGLE_H                   0x60f6
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2          0x6f01
 #define USB_PID_WINFAST_DTV_DONGLE_GOLD                        0x6029
 #define USB_PID_GENPIX_8PSK_REV_1_COLD                 0x0200
 #define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
 #define USB_PID_SONY_PLAYTV                            0x0003
 #define USB_PID_ELGATO_EYETV_DTT                       0x0021
+#define USB_PID_ELGATO_EYETV_DTT_Dlx                   0x0020
 
 #endif
index b5157518a300f01b06eda411862ea106c88ab7d3..e441d274e6c117010f1da2ee91f083782f0823e4 100644 (file)
@@ -223,7 +223,7 @@ struct dvb_usb_device_properties {
        int generic_bulk_ctrl_endpoint;
 
        int num_device_descs;
-       struct dvb_usb_device_description devices[11];
+       struct dvb_usb_device_description devices[12];
 };
 
 /**
index c65f273ff313cda9d874f3183f343949da953169..75de49c0d94370e34e3922b398c5847bf55c7361 100644 (file)
@@ -1,7 +1,7 @@
 /* DVB USB framework compliant Linux driver for the
-*      DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card
-*
-* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*      DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
+*      TeVii S600, S650 Cards
+* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
 *
 *      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
@@ -17,6 +17,7 @@
 #include "stb6000.h"
 #include "eds1547.h"
 #include "cx24116.h"
+#include "tda1002x.h"
 
 #ifndef USB_PID_DW2102
 #define USB_PID_DW2102 0x2102
 #define USB_PID_DW2104 0x2104
 #endif
 
+#ifndef USB_PID_DW3101
+#define USB_PID_DW3101 0x3101
+#endif
+
 #ifndef USB_PID_CINERGY_S
 #define USB_PID_CINERGY_S 0x0064
 #endif
 
+#ifndef USB_PID_TEVII_S650
+#define USB_PID_TEVII_S650 0xd650
+#endif
+
 #define DW210X_READ_MSG 0
 #define DW210X_WRITE_MSG 1
 
 #define DW2102_VOLTAGE_CTRL (0x1800)
 #define DW2102_RC_QUERY (0x1a00)
 
-struct dw210x_state {
-       u32 last_key_pressed;
-};
-struct dw210x_rc_keys {
-       u32 keycode;
-       u32 event;
+struct dvb_usb_rc_keys_table {
+       struct dvb_usb_rc_key *rc_keys;
+       int rc_keys_size;
 };
 
 /* debug */
 static int dvb_usb_dw2102_debug;
 module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
+                                               DVB_USB_DEBUG_STATUS);
+
+/* keymaps */
+static int ir_keymap;
+module_param_named(keymap, ir_keymap, int, 0644);
+MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs  ...");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
@@ -79,7 +91,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
 static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                int num)
 {
-struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i = 0, ret = 0;
        u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
        u16 value;
@@ -205,6 +217,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
        mutex_unlock(&d->i2c_mutex);
        return num;
 }
+
 static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
@@ -219,7 +232,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
        case 2: {
                /* read */
                /* first write first register number */
-               u8 ibuf [msg[1].len + 2], obuf[3];
+               u8 ibuf[msg[1].len + 2], obuf[3];
                obuf[0] = 0xd0;
                obuf[1] = msg[0].len;
                obuf[2] = msg[0].buf[0];
@@ -293,7 +306,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
        case 2: {
                /* read */
                /* first write first register number */
-               u8 ibuf [msg[1].len + 2], obuf[3];
+               u8 ibuf[msg[1].len + 2], obuf[3];
                obuf[0] = 0xaa;
                obuf[1] = msg[0].len;
                obuf[2] = msg[0].buf[0];
@@ -360,6 +373,69 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
        return num;
 }
 
+static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                                                               int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0, i;
+
+       if (!d)
+               return -ENODEV;
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       switch (num) {
+       case 2: {
+               /* read */
+               /* first write first register number */
+               u8 ibuf[msg[1].len + 2], obuf[3];
+               obuf[0] = msg[0].addr << 1;
+               obuf[1] = msg[0].len;
+               obuf[2] = msg[0].buf[0];
+               ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                               obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+               /* second read registers */
+               ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
+                               ibuf, msg[1].len + 2, DW210X_READ_MSG);
+               memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+               break;
+       }
+       case 1:
+               switch (msg[0].addr) {
+               case 0x60:
+               case 0x0c: {
+                       /* write to register */
+                       u8 obuf[msg[0].len + 2];
+                       obuf[0] = msg[0].addr << 1;
+                       obuf[1] = msg[0].len;
+                       memcpy(obuf + 2, msg[0].buf, msg[0].len);
+                       ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                                       obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+                       break;
+               }
+               case(DW2102_RC_QUERY): {
+                       u8 ibuf[2];
+                       ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+                                       ibuf, 2, DW210X_READ_MSG);
+                       memcpy(msg[0].buf, ibuf , 2);
+                       break;
+               }
+               }
+
+               break;
+       }
+
+       for (i = 0; i < num; i++) {
+               deb_xfer("%02x:%02x: %s ", i, msg[i].addr,
+                               msg[i].flags == 0 ? ">>>" : "<<<");
+               debug_dump(msg[i].buf, msg[i].len, deb_xfer);
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return num;
+}
+
 static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C;
@@ -385,6 +461,11 @@ static struct i2c_algorithm dw2104_i2c_algo = {
        .functionality = dw210x_i2c_func,
 };
 
+static struct i2c_algorithm dw3101_i2c_algo = {
+       .master_xfer = dw3101_i2c_transfer,
+       .functionality = dw210x_i2c_func,
+};
+
 static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 {
        int i;
@@ -404,6 +485,7 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
                        debug_dump(eepromline, 16, deb_xfer);
                }
        }
+
        memcpy(mac, eeprom + 8, 6);
        return 0;
 };
@@ -448,6 +530,11 @@ static struct si21xx_config serit_sp1511lhb_config = {
 
 };
 
+static struct tda10023_config dw3101_tda10023_config = {
+       .demod_address = 0x0c,
+       .invert = 1,
+};
+
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
        if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
@@ -460,6 +547,7 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 }
 
 static struct dvb_usb_device_properties dw2102_properties;
+static struct dvb_usb_device_properties dw2104_properties;
 
 static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 {
@@ -497,6 +585,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
        return -EIO;
 }
 
+static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
+{
+       d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
+                               &d->dev->i2c_adap, 0x48);
+       if (d->fe != NULL) {
+               info("Attached tda10023!\n");
+               return 0;
+       }
+       return -EIO;
+}
+
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -512,6 +611,14 @@ static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+               &adap->dev->i2c_adap, DVB_PLL_TUA6034);
+
+       return 0;
+}
+
 static struct dvb_usb_rc_key dw210x_rc_keys[] = {
        { 0xf8, 0x0a, KEY_Q },          /*power*/
        { 0xf8, 0x0c, KEY_M },          /*mute*/
@@ -544,44 +651,147 @@ static struct dvb_usb_rc_key dw210x_rc_keys[] = {
        { 0xf8, 0x40, KEY_F },          /*full*/
        { 0xf8, 0x1e, KEY_W },          /*tvmode*/
        { 0xf8, 0x1b, KEY_B },          /*recall*/
+};
 
+static struct dvb_usb_rc_key tevii_rc_keys[] = {
+       { 0xf8, 0x0a, KEY_POWER },
+       { 0xf8, 0x0c, KEY_MUTE },
+       { 0xf8, 0x11, KEY_1 },
+       { 0xf8, 0x12, KEY_2 },
+       { 0xf8, 0x13, KEY_3 },
+       { 0xf8, 0x14, KEY_4 },
+       { 0xf8, 0x15, KEY_5 },
+       { 0xf8, 0x16, KEY_6 },
+       { 0xf8, 0x17, KEY_7 },
+       { 0xf8, 0x18, KEY_8 },
+       { 0xf8, 0x19, KEY_9 },
+       { 0xf8, 0x10, KEY_0 },
+       { 0xf8, 0x1c, KEY_MENU },
+       { 0xf8, 0x0f, KEY_VOLUMEDOWN },
+       { 0xf8, 0x1a, KEY_LAST },
+       { 0xf8, 0x0e, KEY_OPEN },
+       { 0xf8, 0x04, KEY_RECORD },
+       { 0xf8, 0x09, KEY_VOLUMEUP },
+       { 0xf8, 0x08, KEY_CHANNELUP },
+       { 0xf8, 0x07, KEY_PVR },
+       { 0xf8, 0x0b, KEY_TIME },
+       { 0xf8, 0x02, KEY_RIGHT },
+       { 0xf8, 0x03, KEY_LEFT },
+       { 0xf8, 0x00, KEY_UP },
+       { 0xf8, 0x1f, KEY_OK },
+       { 0xf8, 0x01, KEY_DOWN },
+       { 0xf8, 0x05, KEY_TUNER },
+       { 0xf8, 0x06, KEY_CHANNELDOWN },
+       { 0xf8, 0x40, KEY_PLAYPAUSE },
+       { 0xf8, 0x1e, KEY_REWIND },
+       { 0xf8, 0x1b, KEY_FAVORITES },
+       { 0xf8, 0x1d, KEY_BACK },
+       { 0xf8, 0x4d, KEY_FASTFORWARD },
+       { 0xf8, 0x44, KEY_EPG },
+       { 0xf8, 0x4c, KEY_INFO },
+       { 0xf8, 0x41, KEY_AB },
+       { 0xf8, 0x43, KEY_AUDIO },
+       { 0xf8, 0x45, KEY_SUBTITLE },
+       { 0xf8, 0x4a, KEY_LIST },
+       { 0xf8, 0x46, KEY_F1 },
+       { 0xf8, 0x47, KEY_F2 },
+       { 0xf8, 0x5e, KEY_F3 },
+       { 0xf8, 0x5c, KEY_F4 },
+       { 0xf8, 0x52, KEY_F5 },
+       { 0xf8, 0x5a, KEY_F6 },
+       { 0xf8, 0x56, KEY_MODE },
+       { 0xf8, 0x58, KEY_SWITCHVIDEOMODE },
 };
 
+static struct dvb_usb_rc_key tbs_rc_keys[] = {
+       { 0xf8, 0x84, KEY_POWER },
+       { 0xf8, 0x94, KEY_MUTE },
+       { 0xf8, 0x87, KEY_1 },
+       { 0xf8, 0x86, KEY_2 },
+       { 0xf8, 0x85, KEY_3 },
+       { 0xf8, 0x8b, KEY_4 },
+       { 0xf8, 0x8a, KEY_5 },
+       { 0xf8, 0x89, KEY_6 },
+       { 0xf8, 0x8f, KEY_7 },
+       { 0xf8, 0x8e, KEY_8 },
+       { 0xf8, 0x8d, KEY_9 },
+       { 0xf8, 0x92, KEY_0 },
+       { 0xf8, 0x96, KEY_CHANNELUP },
+       { 0xf8, 0x91, KEY_CHANNELDOWN },
+       { 0xf8, 0x93, KEY_VOLUMEUP },
+       { 0xf8, 0x8c, KEY_VOLUMEDOWN },
+       { 0xf8, 0x83, KEY_RECORD },
+       { 0xf8, 0x98, KEY_PAUSE  },
+       { 0xf8, 0x99, KEY_OK },
+       { 0xf8, 0x9a, KEY_SHUFFLE },
+       { 0xf8, 0x81, KEY_UP },
+       { 0xf8, 0x90, KEY_LEFT },
+       { 0xf8, 0x82, KEY_RIGHT },
+       { 0xf8, 0x88, KEY_DOWN },
+       { 0xf8, 0x95, KEY_FAVORITES },
+       { 0xf8, 0x97, KEY_SUBTITLE },
+       { 0xf8, 0x9d, KEY_ZOOM },
+       { 0xf8, 0x9f, KEY_EXIT },
+       { 0xf8, 0x9e, KEY_MENU },
+       { 0xf8, 0x9c, KEY_EPG },
+       { 0xf8, 0x80, KEY_PREVIOUS },
+       { 0xf8, 0x9b, KEY_MODE }
+};
 
+static struct dvb_usb_rc_keys_table keys_tables[] = {
+       { dw210x_rc_keys, ARRAY_SIZE(dw210x_rc_keys) },
+       { tevii_rc_keys, ARRAY_SIZE(tevii_rc_keys) },
+       { tbs_rc_keys, ARRAY_SIZE(tbs_rc_keys) },
+};
 
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-       struct dw210x_state *st = d->priv;
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       int keymap_size = d->props.rc_key_map_size;
        u8 key[2];
-       struct i2c_msg msg[] = {
-               {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
-               .len = 2},
+       struct i2c_msg msg = {
+               .addr = DW2102_RC_QUERY,
+               .flags = I2C_M_RD,
+               .buf = key,
+               .len = 2
        };
        int i;
+       /* override keymap */
+       if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
+               keymap = keys_tables[ir_keymap - 1].rc_keys ;
+               keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
+       }
 
        *state = REMOTE_NO_KEY_PRESSED;
-       if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
-               for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) {
-                       if (dw210x_rc_keys[i].data == msg[0].buf[0]) {
+       if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) {
+               for (i = 0; i < keymap_size ; i++) {
+                       if (keymap[i].data == msg.buf[0]) {
                                *state = REMOTE_KEY_PRESSED;
-                               *event = dw210x_rc_keys[i].event;
-                               st->last_key_pressed =
-                                       dw210x_rc_keys[i].event;
+                               *event = keymap[i].event;
                                break;
                        }
-               st->last_key_pressed = 0;
+
                }
+
+               if ((*state) == REMOTE_KEY_PRESSED)
+                       deb_rc("%s: found rc key: %x, %x, event: %x\n",
+                                       __func__, key[0], key[1], (*event));
+               else if (key[0] != 0xff)
+                       deb_rc("%s: unknown rc key: %x, %x\n",
+                                       __func__, key[0], key[1]);
+
        }
-       /* info("key: %x %x\n",key[0],key[1]); */
+
        return 0;
 }
 
 static struct usb_device_id dw2102_table[] = {
        {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
        {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
-       {USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
-       {USB_DEVICE(0x9022, 0xd650)},
+       {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
+       {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
        {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+       {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
        { }
 };
 
@@ -642,11 +852,16 @@ static int dw2102_load_firmware(struct usb_device *dev,
                }
                /* init registers */
                switch (dev->descriptor.idProduct) {
+               case USB_PID_TEVII_S650:
+                       dw2104_properties.rc_key_map = tevii_rc_keys;
+                       dw2104_properties.rc_key_map_size =
+                                       ARRAY_SIZE(tevii_rc_keys);
                case USB_PID_DW2104:
-               case 0xd650:
                        reset = 1;
                        dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
                                        DW210X_WRITE_MSG);
+                       /* break omitted intentionally */
+               case USB_PID_DW3101:
                        reset = 0;
                        dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
                                        DW210X_WRITE_MSG);
@@ -690,6 +905,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                                        DW210X_READ_MSG);
                        break;
                }
+
                msleep(100);
                kfree(p);
        }
@@ -700,7 +916,6 @@ static struct dvb_usb_device_properties dw2102_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
        .usb_ctrl = DEVICE_SPECIFIC,
        .firmware = "dvb-usb-dw2102.fw",
-       .size_of_priv = sizeof(struct dw210x_state),
        .no_reconnect = 1,
 
        .i2c_algo = &dw2102_serit_i2c_algo,
@@ -714,7 +929,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
        .num_adapters = 1,
        .download_firmware = dw2102_load_firmware,
        .read_mac_address = dw210x_read_mac_address,
-               .adapter = {
+       .adapter = {
                {
                        .frontend_attach = dw2102_frontend_attach,
                        .streaming_ctrl = NULL,
@@ -752,7 +967,6 @@ static struct dvb_usb_device_properties dw2104_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
        .usb_ctrl = DEVICE_SPECIFIC,
        .firmware = "dvb-usb-dw2104.fw",
-       .size_of_priv = sizeof(struct dw210x_state),
        .no_reconnect = 1,
 
        .i2c_algo = &dw2104_i2c_algo,
@@ -796,12 +1010,57 @@ static struct dvb_usb_device_properties dw2104_properties = {
        }
 };
 
+static struct dvb_usb_device_properties dw3101_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .firmware = "dvb-usb-dw3101.fw",
+       .no_reconnect = 1,
+
+       .i2c_algo = &dw3101_i2c_algo,
+       .rc_key_map = dw210x_rc_keys,
+       .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
+       .rc_interval = 150,
+       .rc_query = dw2102_rc_query,
+
+       .generic_bulk_ctrl_endpoint = 0x81,
+       /* parameter for the MPEG2-data transfer */
+       .num_adapters = 1,
+       .download_firmware = dw2102_load_firmware,
+       .read_mac_address = dw210x_read_mac_address,
+       .adapter = {
+               {
+                       .frontend_attach = dw3101_frontend_attach,
+                       .streaming_ctrl = NULL,
+                       .tuner_attach = dw3101_tuner_attach,
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 8,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
+               }
+       },
+       .num_device_descs = 1,
+       .devices = {
+               { "DVBWorld DVB-C 3101 USB2.0",
+                       {&dw2102_table[5], NULL},
+                       {NULL},
+               },
+       }
+};
+
 static int dw2102_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
        if (0 == dvb_usb_device_init(intf, &dw2102_properties,
                        THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, &dw2104_properties,
+                       THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, &dw3101_properties,
                        THIS_MODULE, NULL, adapter_nr)) {
                return 0;
        }
@@ -833,6 +1092,8 @@ module_init(dw2102_module_init);
 module_exit(dw2102_module_exit);
 
 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
-MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device");
+MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
+                               " DVB-C 3101 USB2.0,"
+                               " TeVii S600, S650 USB2.0 devices");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
index e3370734e95a2d625e736a8718de9d671ab759e1..5cd0b0eb6ce148dc0b0be35bcd0f6a2570c9f1fc 100644 (file)
@@ -5,4 +5,5 @@
 #include "dvb-usb.h"
 
 #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_dw2102_debug, 0x04, args)
 #endif
index 3dd6843864ed8a05f33baedd437af45bff412c86..afb444db43ad971df82b810ad09485cefc5c8a9b 100644 (file)
@@ -223,7 +223,7 @@ static struct usb_device_id gp8psk_usb_table [] = {
            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
-           { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) },
+/*         { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
            { 0 },
 };
 MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
@@ -254,7 +254,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .num_device_descs = 4,
+       .num_device_descs = 3,
        .devices = {
                { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
                  .cold_ids = { &gp8psk_usb_table[0], NULL },
@@ -268,10 +268,6 @@ static struct dvb_usb_device_properties gp8psk_properties = {
                  .cold_ids = { NULL },
                  .warm_ids = { &gp8psk_usb_table[3], NULL },
                },
-               { .name = "Genpix SkyWalker-CW3K DVB-S receiver",
-                 .cold_ids = { NULL },
-                 .warm_ids = { &gp8psk_usb_table[4], NULL },
-               },
                { NULL },
        }
 };
index 46a6324d7b730fe0e0b1ab2212ad32ab582aa213..27bca2e283dfc4a0a00ea070da033788997b27df 100644 (file)
@@ -18,7 +18,7 @@
 #include "firedtv.h"
 
 /* fixed table with older keycodes, geared towards MythTV */
-const static u16 oldtable[] = {
+static const u16 oldtable[] = {
 
        /* code from device: 0x4501...0x451f */
 
@@ -62,7 +62,7 @@ const static u16 oldtable[] = {
 };
 
 /* user-modifiable table for a remote as sold in 2008 */
-const static u16 keytable[] = {
+static const u16 keytable[] = {
 
        /* code from device: 0x0300...0x031f */
 
index 23e4cffeba38a789f1e03359c35a66685501dd71..be967ac09a3962e3f704a862998dfd43574d586d 100644 (file)
@@ -35,6 +35,21 @@ config DVB_STB6100
          A Silicon tuner from ST used in conjunction with the STB0899
          demodulator. Say Y when you want to support this tuner.
 
+config DVB_STV090x
+       tristate "STV0900/STV0903(A/B) based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
+         Say Y when you want to support these frontends.
+
+config DVB_STV6110x
+       tristate "STV6110/(A) based tuners"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A Silicon tuner that supports DVB-S and DVB-S2 modes
+
 comment "DVB-S (satellite) frontends"
        depends on DVB_CORE
 
@@ -506,6 +521,13 @@ config DVB_ISL6421
        help
          An SEC control chip.
 
+config DVB_ISL6423
+       tristate "ISL6423 SEC controller"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A SEC controller chip from Intersil
+
 config DVB_LGS8GL5
        tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
        depends on DVB_CORE && I2C
index bc2b00abd1064612310cc58d9f3ae98ffacb0a37..832473c1e512765feb454597c8fd55d19053b166 100644 (file)
@@ -71,4 +71,6 @@ obj-$(CONFIG_DVB_STB6000) += stb6000.o
 obj-$(CONFIG_DVB_S921) += s921.o
 obj-$(CONFIG_DVB_STV6110) += stv6110.o
 obj-$(CONFIG_DVB_STV0900) += stv0900.o
-
+obj-$(CONFIG_DVB_STV090x) += stv090x.o
+obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
+obj-$(CONFIG_DVB_ISL6423) += isl6423.o
index b2b50fb4cfd338002102b868e87b0cac1032954a..136c5863d81b5859d38fefd33b496932e8f6cca5 100644 (file)
@@ -1455,7 +1455,7 @@ static int af9013_download_firmware(struct af9013_state *state)
                af9013_ops.info.name);
 
        /* request the firmware, this will block and timeout */
-       ret = request_firmware(&fw, fw_file,  &state->i2c->dev);
+       ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
        if (ret) {
                err("did not find the firmware file. (%s) "
                        "Please see linux/Documentation/dvb/ for more details" \
index 35731258bb0a7b6d2025c7df0192c5e5bba8a2d7..956b80f4979ca95af361162ec6adde484a1c9c89 100644 (file)
@@ -367,11 +367,90 @@ static struct {
        { 0x8231, 0x13 },
 };
 
-/* QAM Modulation table */
+/* QAM64 Modulation table */
 static struct {
        u16 reg;
        u16 data;
-} QAM_mod_tab[] = {
+} QAM64_mod_tab[] = {
+       { 0x00a3, 0x09 },
+       { 0x00a4, 0x00 },
+       { 0x0081, 0xc4 },
+       { 0x00a5, 0x40 },
+       { 0x00aa, 0x77 },
+       { 0x00ad, 0x77 },
+       { 0x00a6, 0x67 },
+       { 0x0262, 0x20 },
+       { 0x021c, 0x30 },
+       { 0x00b8, 0x3e },
+       { 0x00b9, 0xf0 },
+       { 0x00ba, 0x01 },
+       { 0x00bb, 0x18 },
+       { 0x00bc, 0x50 },
+       { 0x00bd, 0x00 },
+       { 0x00be, 0xea },
+       { 0x00bf, 0xef },
+       { 0x00c0, 0xfc },
+       { 0x00c1, 0xbd },
+       { 0x00c2, 0x1f },
+       { 0x00c3, 0xfc },
+       { 0x00c4, 0xdd },
+       { 0x00c5, 0xaf },
+       { 0x00c6, 0x00 },
+       { 0x00c7, 0x38 },
+       { 0x00c8, 0x30 },
+       { 0x00c9, 0x05 },
+       { 0x00ca, 0x4a },
+       { 0x00cb, 0xd0 },
+       { 0x00cc, 0x01 },
+       { 0x00cd, 0xd9 },
+       { 0x00ce, 0x6f },
+       { 0x00cf, 0xf9 },
+       { 0x00d0, 0x70 },
+       { 0x00d1, 0xdf },
+       { 0x00d2, 0xf7 },
+       { 0x00d3, 0xc2 },
+       { 0x00d4, 0xdf },
+       { 0x00d5, 0x02 },
+       { 0x00d6, 0x9a },
+       { 0x00d7, 0xd0 },
+       { 0x0250, 0x0d },
+       { 0x0251, 0xcd },
+       { 0x0252, 0xe0 },
+       { 0x0253, 0x05 },
+       { 0x0254, 0xa7 },
+       { 0x0255, 0xff },
+       { 0x0256, 0xed },
+       { 0x0257, 0x5b },
+       { 0x0258, 0xae },
+       { 0x0259, 0xe6 },
+       { 0x025a, 0x3d },
+       { 0x025b, 0x0f },
+       { 0x025c, 0x0d },
+       { 0x025d, 0xea },
+       { 0x025e, 0xf2 },
+       { 0x025f, 0x51 },
+       { 0x0260, 0xf5 },
+       { 0x0261, 0x06 },
+       { 0x021a, 0x00 },
+       { 0x0546, 0x40 },
+       { 0x0210, 0xc7 },
+       { 0x0211, 0xaa },
+       { 0x0212, 0xab },
+       { 0x0213, 0x02 },
+       { 0x0502, 0x00 },
+       { 0x0121, 0x04 },
+       { 0x0122, 0x04 },
+       { 0x052e, 0x10 },
+       { 0x00a4, 0xca },
+       { 0x00a7, 0x40 },
+       { 0x0526, 0x01 },
+};
+
+/* QAM256 Modulation table */
+static struct {
+       u16 reg;
+       u16 data;
+} QAM256_mod_tab[] = {
        { 0x80a3, 0x09 },
        { 0x80a4, 0x00 },
        { 0x8081, 0xc4 },
@@ -464,12 +543,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
                au8522_set_if(fe, state->config->vsb_if);
                break;
        case QAM_64:
+               dprintk("%s() QAM 64\n", __func__);
+               for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
+                       au8522_writereg(state,
+                               QAM64_mod_tab[i].reg,
+                               QAM64_mod_tab[i].data);
+               au8522_set_if(fe, state->config->qam_if);
+               break;
        case QAM_256:
-               dprintk("%s() QAM 64/256\n", __func__);
-               for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
+               dprintk("%s() QAM 256\n", __func__);
+               for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
                        au8522_writereg(state,
-                               QAM_mod_tab[i].reg,
-                               QAM_mod_tab[i].data);
+                               QAM256_mod_tab[i].reg,
+                               QAM256_mod_tab[i].data);
                au8522_set_if(fe, state->config->qam_if);
                break;
        default:
index 9b9f57264ceff0bd76c7685477ae22486d2a4b5a..2410d8b59b6b428aa7621ed8b71839bef23282a8 100644 (file)
@@ -492,7 +492,7 @@ static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
                printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
                        __func__, CX24116_DEFAULT_FIRMWARE);
                ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
-                       &state->i2c->dev);
+                       state->i2c->dev.parent);
                printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
                        __func__);
                if (ret) {
index 172f1f928f0271f8e64bc7daa12ea999033ee2d6..0100755352216ef3d180a270009a2bcde20b76bc 100644 (file)
@@ -123,10 +123,10 @@ static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix)
        }
        memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
 
-       if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) {
+       rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent);
+       if (rc != 0) {
                printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
                       mod_name, fw[ix].name);
-               rc = -ENOENT;
                goto exit_err;
        }
 
diff --git a/drivers/media/dvb/frontends/isl6423.c b/drivers/media/dvb/frontends/isl6423.c
new file mode 100644 (file)
index 0000000..dca5beb
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+       Intersil ISL6423 SEC and LNB Power supply controller
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6423.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+#define FE_ERROR                               0
+#define FE_NOTICE                              1
+#define FE_INFO                                        2
+#define FE_DEBUG                               3
+#define FE_DEBUGREG                            4
+
+#define dprintk(__y, __z, format, arg...) do {                                         \
+       if (__z) {                                                                      \
+               if      ((verbose > FE_ERROR) && (verbose > __y))                       \
+                       printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);          \
+               else if ((verbose > FE_NOTICE) && (verbose > __y))                      \
+                       printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);       \
+               else if ((verbose > FE_INFO) && (verbose > __y))                        \
+                       printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);         \
+               else if ((verbose > FE_DEBUG) && (verbose > __y))                       \
+                       printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);        \
+       } else {                                                                        \
+               if (verbose > __y)                                                      \
+                       printk(format, ##arg);                                          \
+       }                                                                               \
+} while (0)
+
+struct isl6423_dev {
+       const struct isl6423_config     *config;
+       struct i2c_adapter              *i2c;
+
+       u8 reg_3;
+       u8 reg_4;
+
+       unsigned int verbose;
+};
+
+static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
+{
+       struct i2c_adapter *i2c = isl6423->i2c;
+       u8 addr                 = isl6423->config->addr;
+       int err = 0;
+
+       struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
+
+       dprintk(FE_DEBUG, 1, "write reg %02X", reg);
+       err = i2c_transfer(i2c, &msg, 1);
+       if (err < 0)
+               goto exit;
+       return 0;
+
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+static int isl6423_set_modulation(struct dvb_frontend *fe)
+{
+       struct isl6423_dev *isl6423             = (struct isl6423_dev *) fe->sec_priv;
+       const struct isl6423_config *config     = isl6423->config;
+       int err = 0;
+       u8 reg_2 = 0;
+
+       reg_2 = 0x01 << 5;
+
+       if (config->mod_extern)
+               reg_2 |= (1 << 3);
+       else
+               reg_2 |= (1 << 4);
+
+       err = isl6423_write(isl6423, reg_2);
+       if (err < 0)
+               goto exit;
+       return 0;
+
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
+{
+       struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
+       u8 reg_3 = isl6423->reg_3;
+       u8 reg_4 = isl6423->reg_4;
+       int err = 0;
+
+       if (arg) {
+               /* EN = 1, VSPEN = 1, VBOT = 1 */
+               reg_4 |= (1 << 4);
+               reg_4 |= 0x1;
+               reg_3 |= (1 << 3);
+       } else {
+               /* EN = 1, VSPEN = 1, VBOT = 0 */
+               reg_4 |= (1 << 4);
+               reg_4 &= ~0x1;
+               reg_3 |= (1 << 3);
+       }
+       err = isl6423_write(isl6423, reg_3);
+       if (err < 0)
+               goto exit;
+
+       err = isl6423_write(isl6423, reg_4);
+       if (err < 0)
+               goto exit;
+
+       isl6423->reg_3 = reg_3;
+       isl6423->reg_4 = reg_4;
+
+       return 0;
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+
+static int isl6423_set_voltage(struct dvb_frontend *fe,
+                              enum fe_sec_voltage voltage)
+{
+       struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
+       u8 reg_3 = isl6423->reg_3;
+       u8 reg_4 = isl6423->reg_4;
+       int err = 0;
+
+       switch (voltage) {
+       case SEC_VOLTAGE_OFF:
+               /* EN = 0 */
+               reg_4 &= ~(1 << 4);
+               break;
+
+       case SEC_VOLTAGE_13:
+               /* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
+               reg_4 |= (1 << 4);
+               reg_4 &= ~0x3;
+               reg_3 |= (1 << 3);
+               break;
+
+       case SEC_VOLTAGE_18:
+               /* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
+               reg_4 |= (1 << 4);
+               reg_4 |=  0x2;
+               reg_4 &= ~0x1;
+               reg_3 |= (1 << 3);
+               break;
+
+       default:
+               break;
+       }
+       err = isl6423_write(isl6423, reg_3);
+       if (err < 0)
+               goto exit;
+
+       err = isl6423_write(isl6423, reg_4);
+       if (err < 0)
+               goto exit;
+
+       isl6423->reg_3 = reg_3;
+       isl6423->reg_4 = reg_4;
+
+       return 0;
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+static int isl6423_set_current(struct dvb_frontend *fe)
+{
+       struct isl6423_dev *isl6423             = (struct isl6423_dev *) fe->sec_priv;
+       u8 reg_3 = isl6423->reg_3;
+       const struct isl6423_config *config     = isl6423->config;
+       int err = 0;
+
+       switch (config->current_max) {
+       case SEC_CURRENT_275m:
+               /* 275mA */
+               /* ISELH = 0, ISELL = 0 */
+               reg_3 &= ~0x3;
+               break;
+
+       case SEC_CURRENT_515m:
+               /* 515mA */
+               /* ISELH = 0, ISELL = 1 */
+               reg_3 &= ~0x2;
+               reg_3 |=  0x1;
+               break;
+
+       case SEC_CURRENT_635m:
+               /* 635mA */
+               /* ISELH = 1, ISELL = 0 */
+               reg_3 &= ~0x1;
+               reg_3 |=  0x2;
+               break;
+
+       case SEC_CURRENT_800m:
+               /* 800mA */
+               /* ISELH = 1, ISELL = 1 */
+               reg_3 |= 0x3;
+               break;
+       }
+
+       err = isl6423_write(isl6423, reg_3);
+       if (err < 0)
+               goto exit;
+
+       switch (config->curlim) {
+       case SEC_CURRENT_LIM_ON:
+               /* DCL = 0 */
+               reg_3 &= ~0x10;
+               break;
+
+       case SEC_CURRENT_LIM_OFF:
+               /* DCL = 1 */
+               reg_3 |= 0x10;
+               break;
+       }
+
+       err = isl6423_write(isl6423, reg_3);
+       if (err < 0)
+               goto exit;
+
+       isl6423->reg_3 = reg_3;
+
+       return 0;
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+static void isl6423_release(struct dvb_frontend *fe)
+{
+       isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+       kfree(fe->sec_priv);
+       fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+                                   struct i2c_adapter *i2c,
+                                   const struct isl6423_config *config)
+{
+       struct isl6423_dev *isl6423;
+
+       isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
+       if (!isl6423)
+               return NULL;
+
+       isl6423->config = config;
+       isl6423->i2c    = i2c;
+       fe->sec_priv    = isl6423;
+
+       /* SR3H = 0, SR3M = 1, SR3L = 0 */
+       isl6423->reg_3 = 0x02 << 5;
+       /* SR4H = 0, SR4M = 1, SR4L = 1 */
+       isl6423->reg_4 = 0x03 << 5;
+
+       if (isl6423_set_current(fe))
+               goto exit;
+
+       if (isl6423_set_modulation(fe))
+               goto exit;
+
+       fe->ops.release_sec             = isl6423_release;
+       fe->ops.set_voltage             = isl6423_set_voltage;
+       fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
+       isl6423->verbose                = verbose;
+
+       return fe;
+
+exit:
+       kfree(isl6423);
+       fe->sec_priv = NULL;
+       return NULL;
+}
+EXPORT_SYMBOL(isl6423_attach);
+
+MODULE_DESCRIPTION("ISL6423 SEC");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6423.h b/drivers/media/dvb/frontends/isl6423.h
new file mode 100644 (file)
index 0000000..e1a37fb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+       Intersil ISL6423 SEC and LNB Power supply controller
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.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 __ISL_6423_H
+#define __ISL_6423_H
+
+#include <linux/dvb/frontend.h>
+
+enum isl6423_current {
+       SEC_CURRENT_275m = 0,
+       SEC_CURRENT_515m,
+       SEC_CURRENT_635m,
+       SEC_CURRENT_800m,
+};
+
+enum isl6423_curlim {
+       SEC_CURRENT_LIM_ON = 1,
+       SEC_CURRENT_LIM_OFF
+};
+
+struct isl6423_config {
+       enum isl6423_current current_max;
+       enum isl6423_curlim curlim;
+       u8 addr;
+       u8 mod_extern;
+};
+
+#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE))
+
+
+extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+                                          struct i2c_adapter *i2c,
+                                          const struct isl6423_config *config);
+
+#else
+static inline struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+                                                 struct i2c_adapter *i2c,
+                                                 const struct isl6423_config *config)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif /* CONFIG_DVB_ISL6423 */
+
+#endif /* __ISL_6423_H */
index d92d0557a80b719cdcf3e99bc876df6d56bad2eb..fde8c59700fbee05d63b6b6433adedd7ec9499a9 100644 (file)
@@ -19,6 +19,7 @@
  *
  */
 
+#include <asm/div64.h>
 #include <linux/dvb/frontend.h>
 #include "dvb_math.h"
 #include "lgdt3305.h"
@@ -496,27 +497,15 @@ static int lgdt3305_set_if(struct lgdt3305_state *state,
 
        nco = if_freq_khz / 10;
 
-#define LGDT3305_64BIT_DIVISION_ENABLED 0
-       /* FIXME: 64bit division disabled to avoid linking error:
-        * WARNING: "__udivdi3" [lgdt3305.ko] undefined!
-        */
        switch (param->u.vsb.modulation) {
        case VSB_8:
-#if LGDT3305_64BIT_DIVISION_ENABLED
                nco <<= 24;
-               nco /= 625;
-#else
-               nco *= ((1 << 24) / 625);
-#endif
+               do_div(nco, 625);
                break;
        case QAM_64:
        case QAM_256:
-#if LGDT3305_64BIT_DIVISION_ENABLED
                nco <<= 28;
-               nco /= 625;
-#else
-               nco *= ((1 << 28) / 625);
-#endif
+               do_div(nco, 625);
                break;
        default:
                return -EINVAL;
index f9785dfe735b770d25cc4efddf8d82fdb59d5371..fde27645bbed67918aca946c1f551dee7a961cea 100644 (file)
        } while (0)
 
 static int debug;
-static int fake_signal_str;
+static int fake_signal_str = 1;
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 module_param(fake_signal_str, int, 0644);
 MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
-"Signal strength calculation is slow.(default:off).");
+"Signal strength calculation is slow.(default:on).");
 
 /* LGS8GXX internal helper functions */
 
@@ -610,7 +610,7 @@ static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
        else
                cat = 0;
 
-       *signal = cat;
+       *signal = cat * 65535 / 5;
 
        return 0;
 }
@@ -630,8 +630,8 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
 
        if (fake_signal_str) {
                if ((t & 0xC0) == 0xC0) {
-                       dprintk("Fake signal strength as 50\n");
-                       *signal = 0x32;
+                       dprintk("Fake signal strength\n");
+                       *signal = 0x7FFF;
                } else
                        *signal = 0;
                return 0;
index 1dcc56f32bff71e92a1c1b94e9ef2463bbe4b725..71f607fe8fc7ca87326ad21e3fbf8fd7eeba9983 100644 (file)
@@ -133,7 +133,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
        /* override frontend ops */
        fe->ops.set_voltage = lnbp21_set_voltage;
        fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-       printk(KERN_INFO "LNBx2x attached on addr=%x", lnbp21->i2c_addr);
+       printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
 
        return fe;
 }
index 5ac9b15920f8df47f8c8d11b10d93a14c972401d..a621f727935f217eb91f78e84a025bfc7a36767b 100644 (file)
@@ -77,7 +77,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
        ret = i2c_transfer(state->i2c, msg, 2);
 
        if (ret != 2) {
-               printk(KERN_ERR "%s: ret == %d\n", __func__, ret);
+               printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret);
                return -EREMOTEIO;
        }
 
index a8429ebfa8a2e6da67208e926d5644f74e583a02..eac20650499fb510217a1ccf4bba9598083f60c7 100644 (file)
@@ -879,7 +879,8 @@ static int nxt2002_init(struct dvb_frontend* fe)
 
        /* request the firmware, this will block until someone uploads it */
        printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
-       ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev);
+       ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE,
+                              state->i2c->dev.parent);
        printk("nxt2002: Waiting for firmware upload(2)...\n");
        if (ret) {
                printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
@@ -943,7 +944,8 @@ static int nxt2004_init(struct dvb_frontend* fe)
 
        /* request the firmware, this will block until someone uploads it */
        printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
-       ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev);
+       ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE,
+                              state->i2c->dev.parent);
        printk("nxt2004: Waiting for firmware upload(2)...\n");
        if (ret) {
                printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");
index 5ed32544de3964798a38f6683109acd92b693971..8133ea3cddd783023ff581c47c904b412ac47c0f 100644 (file)
@@ -340,7 +340,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
                }
                printk("or51132: Waiting for firmware upload(%s)...\n",
                       fwname);
-               ret = request_firmware(&fw, fwname, &state->i2c->dev);
+               ret = request_firmware(&fw, fwname, state->i2c->dev.parent);
                if (ret) {
                        printk(KERN_WARNING "or51132: No firmware up"
                               "loaded(timeout or file not found?)\n");
index 762d5af62d7a38bab2e944428a55f69fdaa7cf01..67dc8ec634e2da56790dc7ab17a5f8c57bc7dc58 100644 (file)
@@ -60,8 +60,6 @@
                } \
        } while (0)
 
-#define dmd_choose(a, b)       (demod = STV0900_DEMOD_2 ? b : a))
-
 static int stvdebug;
 
 #define dprintk(args...) \
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
new file mode 100644 (file)
index 0000000..96ef745
--- /dev/null
@@ -0,0 +1,4299 @@
+/*
+       STV0900/0903 Multistandard Broadcast Frontend driver
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#include "stv6110x.h" /* for demodulator internal modes */
+
+#include "stv090x_reg.h"
+#include "stv090x.h"
+#include "stv090x_priv.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+
+struct mutex demod_lock;
+
+/* DVBS1 and DSS C/N Lookup table */
+static const struct stv090x_tab stv090x_s1cn_tab[] = {
+       {   0, 8917 }, /*  0.0dB */
+       {   5, 8801 }, /*  0.5dB */
+       {  10, 8667 }, /*  1.0dB */
+       {  15, 8522 }, /*  1.5dB */
+       {  20, 8355 }, /*  2.0dB */
+       {  25, 8175 }, /*  2.5dB */
+       {  30, 7979 }, /*  3.0dB */
+       {  35, 7763 }, /*  3.5dB */
+       {  40, 7530 }, /*  4.0dB */
+       {  45, 7282 }, /*  4.5dB */
+       {  50, 7026 }, /*  5.0dB */
+       {  55, 6781 }, /*  5.5dB */
+       {  60, 6514 }, /*  6.0dB */
+       {  65, 6241 }, /*  6.5dB */
+       {  70, 5965 }, /*  7.0dB */
+       {  75, 5690 }, /*  7.5dB */
+       {  80, 5424 }, /*  8.0dB */
+       {  85, 5161 }, /*  8.5dB */
+       {  90, 4902 }, /*  9.0dB */
+       {  95, 4654 }, /*  9.5dB */
+       { 100, 4417 }, /* 10.0dB */
+       { 105, 4186 }, /* 10.5dB */
+       { 110, 3968 }, /* 11.0dB */
+       { 115, 3757 }, /* 11.5dB */
+       { 120, 3558 }, /* 12.0dB */
+       { 125, 3366 }, /* 12.5dB */
+       { 130, 3185 }, /* 13.0dB */
+       { 135, 3012 }, /* 13.5dB */
+       { 140, 2850 }, /* 14.0dB */
+       { 145, 2698 }, /* 14.5dB */
+       { 150, 2550 }, /* 15.0dB */
+       { 160, 2283 }, /* 16.0dB */
+       { 170, 2042 }, /* 17.0dB */
+       { 180, 1827 }, /* 18.0dB */
+       { 190, 1636 }, /* 19.0dB */
+       { 200, 1466 }, /* 20.0dB */
+       { 210, 1315 }, /* 21.0dB */
+       { 220, 1181 }, /* 22.0dB */
+       { 230, 1064 }, /* 23.0dB */
+       { 240,  960 }, /* 24.0dB */
+       { 250,  869 }, /* 25.0dB */
+       { 260,  792 }, /* 26.0dB */
+       { 270,  724 }, /* 27.0dB */
+       { 280,  665 }, /* 28.0dB */
+       { 290,  616 }, /* 29.0dB */
+       { 300,  573 }, /* 30.0dB */
+       { 310,  537 }, /* 31.0dB */
+       { 320,  507 }, /* 32.0dB */
+       { 330,  483 }, /* 33.0dB */
+       { 400,  398 }, /* 40.0dB */
+       { 450,  381 }, /* 45.0dB */
+       { 500,  377 }  /* 50.0dB */
+};
+
+/* DVBS2 C/N Lookup table */
+static const struct stv090x_tab stv090x_s2cn_tab[] = {
+       { -30, 13348 }, /* -3.0dB */
+       { -20, 12640 }, /* -2d.0B */
+       { -10, 11883 }, /* -1.0dB */
+       {   0, 11101 }, /* -0.0dB */
+       {   5, 10718 }, /*  0.5dB */
+       {  10, 10339 }, /*  1.0dB */
+       {  15,  9947 }, /*  1.5dB */
+       {  20,  9552 }, /*  2.0dB */
+       {  25,  9183 }, /*  2.5dB */
+       {  30,  8799 }, /*  3.0dB */
+       {  35,  8422 }, /*  3.5dB */
+       {  40,  8062 }, /*  4.0dB */
+       {  45,  7707 }, /*  4.5dB */
+       {  50,  7353 }, /*  5.0dB */
+       {  55,  7025 }, /*  5.5dB */
+       {  60,  6684 }, /*  6.0dB */
+       {  65,  6331 }, /*  6.5dB */
+       {  70,  6036 }, /*  7.0dB */
+       {  75,  5727 }, /*  7.5dB */
+       {  80,  5437 }, /*  8.0dB */
+       {  85,  5164 }, /*  8.5dB */
+       {  90,  4902 }, /*  9.0dB */
+       {  95,  4653 }, /*  9.5dB */
+       { 100,  4408 }, /* 10.0dB */
+       { 105,  4187 }, /* 10.5dB */
+       { 110,  3961 }, /* 11.0dB */
+       { 115,  3751 }, /* 11.5dB */
+       { 120,  3558 }, /* 12.0dB */
+       { 125,  3368 }, /* 12.5dB */
+       { 130,  3191 }, /* 13.0dB */
+       { 135,  3017 }, /* 13.5dB */
+       { 140,  2862 }, /* 14.0dB */
+       { 145,  2710 }, /* 14.5dB */
+       { 150,  2565 }, /* 15.0dB */
+       { 160,  2300 }, /* 16.0dB */
+       { 170,  2058 }, /* 17.0dB */
+       { 180,  1849 }, /* 18.0dB */
+       { 190,  1663 }, /* 19.0dB */
+       { 200,  1495 }, /* 20.0dB */
+       { 210,  1349 }, /* 21.0dB */
+       { 220,  1222 }, /* 22.0dB */
+       { 230,  1110 }, /* 23.0dB */
+       { 240,  1011 }, /* 24.0dB */
+       { 250,   925 }, /* 25.0dB */
+       { 260,   853 }, /* 26.0dB */
+       { 270,   789 }, /* 27.0dB */
+       { 280,   734 }, /* 28.0dB */
+       { 290,   690 }, /* 29.0dB */
+       { 300,   650 }, /* 30.0dB */
+       { 310,   619 }, /* 31.0dB */
+       { 320,   593 }, /* 32.0dB */
+       { 330,   571 }, /* 33.0dB */
+       { 400,   498 }, /* 40.0dB */
+       { 450,   484 }, /* 45.0dB */
+       { 500,   481 }  /* 50.0dB */
+};
+
+/* RF level C/N lookup table */
+static const struct stv090x_tab stv090x_rf_tab[] = {
+       {  -5, 0xcaa1 }, /*  -5dBm */
+       { -10, 0xc229 }, /* -10dBm */
+       { -15, 0xbb08 }, /* -15dBm */
+       { -20, 0xb4bc }, /* -20dBm */
+       { -25, 0xad5a }, /* -25dBm */
+       { -30, 0xa298 }, /* -30dBm */
+       { -35, 0x98a8 }, /* -35dBm */
+       { -40, 0x8389 }, /* -40dBm */
+       { -45, 0x59be }, /* -45dBm */
+       { -50, 0x3a14 }, /* -50dBm */
+       { -55, 0x2d11 }, /* -55dBm */
+       { -60, 0x210d }, /* -60dBm */
+       { -65, 0xa14f }, /* -65dBm */
+       { -70, 0x07aa }  /* -70dBm */
+};
+
+
+static struct stv090x_reg stv0900_initval[] = {
+
+       { STV090x_OUTCFG,               0x00 },
+       { STV090x_MODECFG,              0xff },
+       { STV090x_AGCRF1CFG,            0x11 },
+       { STV090x_AGCRF2CFG,            0x13 },
+       { STV090x_TSGENERAL1X,          0x14 },
+       { STV090x_TSTTNR2,              0x21 },
+       { STV090x_TSTTNR4,              0x21 },
+       { STV090x_P2_DISTXCTL,          0x22 },
+       { STV090x_P2_F22TX,             0xc0 },
+       { STV090x_P2_F22RX,             0xc0 },
+       { STV090x_P2_DISRXCTL,          0x00 },
+       { STV090x_P2_DMDCFGMD,          0xF9 },
+       { STV090x_P2_DEMOD,             0x08 },
+       { STV090x_P2_DMDCFG3,           0xc4 },
+       { STV090x_P2_CARFREQ,           0xed },
+       { STV090x_P2_LDT,               0xd0 },
+       { STV090x_P2_LDT2,              0xb8 },
+       { STV090x_P2_TMGCFG,            0xd2 },
+       { STV090x_P2_TMGTHRISE,         0x20 },
+       { STV090x_P1_TMGCFG,            0xd2 },
+
+       { STV090x_P2_TMGTHFALL,         0x00 },
+       { STV090x_P2_FECSPY,            0x88 },
+       { STV090x_P2_FSPYDATA,          0x3a },
+       { STV090x_P2_FBERCPT4,          0x00 },
+       { STV090x_P2_FSPYBER,           0x10 },
+       { STV090x_P2_ERRCTRL1,          0x35 },
+       { STV090x_P2_ERRCTRL2,          0xc1 },
+       { STV090x_P2_CFRICFG,           0xf8 },
+       { STV090x_P2_NOSCFG,            0x1c },
+       { STV090x_P2_DMDTOM,            0x20 },
+       { STV090x_P2_CORRELMANT,        0x70 },
+       { STV090x_P2_CORRELABS,         0x88 },
+       { STV090x_P2_AGC2O,             0x5b },
+       { STV090x_P2_AGC2REF,           0x38 },
+       { STV090x_P2_CARCFG,            0xe4 },
+       { STV090x_P2_ACLC,              0x1A },
+       { STV090x_P2_BCLC,              0x09 },
+       { STV090x_P2_CARHDR,            0x08 },
+       { STV090x_P2_KREFTMG,           0xc1 },
+       { STV090x_P2_SFRUPRATIO,        0xf0 },
+       { STV090x_P2_SFRLOWRATIO,       0x70 },
+       { STV090x_P2_SFRSTEP,           0x58 },
+       { STV090x_P2_TMGCFG2,           0x01 },
+       { STV090x_P2_CAR2CFG,           0x26 },
+       { STV090x_P2_BCLC2S2Q,          0x86 },
+       { STV090x_P2_BCLC2S28,          0x86 },
+       { STV090x_P2_SMAPCOEF7,         0x77 },
+       { STV090x_P2_SMAPCOEF6,         0x85 },
+       { STV090x_P2_SMAPCOEF5,         0x77 },
+       { STV090x_P2_TSCFGL,            0x20 },
+       { STV090x_P2_DMDCFG2,           0x3b },
+       { STV090x_P2_MODCODLST0,        0xff },
+       { STV090x_P2_MODCODLST1,        0xff },
+       { STV090x_P2_MODCODLST2,        0xff },
+       { STV090x_P2_MODCODLST3,        0xff },
+       { STV090x_P2_MODCODLST4,        0xff },
+       { STV090x_P2_MODCODLST5,        0xff },
+       { STV090x_P2_MODCODLST6,        0xff },
+       { STV090x_P2_MODCODLST7,        0xcc },
+       { STV090x_P2_MODCODLST8,        0xcc },
+       { STV090x_P2_MODCODLST9,        0xcc },
+       { STV090x_P2_MODCODLSTA,        0xcc },
+       { STV090x_P2_MODCODLSTB,        0xcc },
+       { STV090x_P2_MODCODLSTC,        0xcc },
+       { STV090x_P2_MODCODLSTD,        0xcc },
+       { STV090x_P2_MODCODLSTE,        0xcc },
+       { STV090x_P2_MODCODLSTF,        0xcf },
+       { STV090x_P1_DISTXCTL,          0x22 },
+       { STV090x_P1_F22TX,             0xc0 },
+       { STV090x_P1_F22RX,             0xc0 },
+       { STV090x_P1_DISRXCTL,          0x00 },
+       { STV090x_P1_DMDCFGMD,          0xf9 },
+       { STV090x_P1_DEMOD,             0x08 },
+       { STV090x_P1_DMDCFG3,           0xc4 },
+       { STV090x_P1_DMDTOM,            0x20 },
+       { STV090x_P1_CARFREQ,           0xed },
+       { STV090x_P1_LDT,               0xd0 },
+       { STV090x_P1_LDT2,              0xb8 },
+       { STV090x_P1_TMGCFG,            0xd2 },
+       { STV090x_P1_TMGTHRISE,         0x20 },
+       { STV090x_P1_TMGTHFALL,         0x00 },
+       { STV090x_P1_SFRUPRATIO,        0xf0 },
+       { STV090x_P1_SFRLOWRATIO,       0x70 },
+       { STV090x_P1_TSCFGL,            0x20 },
+       { STV090x_P1_FECSPY,            0x88 },
+       { STV090x_P1_FSPYDATA,          0x3a },
+       { STV090x_P1_FBERCPT4,          0x00 },
+       { STV090x_P1_FSPYBER,           0x10 },
+       { STV090x_P1_ERRCTRL1,          0x35 },
+       { STV090x_P1_ERRCTRL2,          0xc1 },
+       { STV090x_P1_CFRICFG,           0xf8 },
+       { STV090x_P1_NOSCFG,            0x1c },
+       { STV090x_P1_CORRELMANT,        0x70 },
+       { STV090x_P1_CORRELABS,         0x88 },
+       { STV090x_P1_AGC2O,             0x5b },
+       { STV090x_P1_AGC2REF,           0x38 },
+       { STV090x_P1_CARCFG,            0xe4 },
+       { STV090x_P1_ACLC,              0x1A },
+       { STV090x_P1_BCLC,              0x09 },
+       { STV090x_P1_CARHDR,            0x08 },
+       { STV090x_P1_KREFTMG,           0xc1 },
+       { STV090x_P1_SFRSTEP,           0x58 },
+       { STV090x_P1_TMGCFG2,           0x01 },
+       { STV090x_P1_CAR2CFG,           0x26 },
+       { STV090x_P1_BCLC2S2Q,          0x86 },
+       { STV090x_P1_BCLC2S28,          0x86 },
+       { STV090x_P1_SMAPCOEF7,         0x77 },
+       { STV090x_P1_SMAPCOEF6,         0x85 },
+       { STV090x_P1_SMAPCOEF5,         0x77 },
+       { STV090x_P1_DMDCFG2,           0x3b },
+       { STV090x_P1_MODCODLST0,        0xff },
+       { STV090x_P1_MODCODLST1,        0xff },
+       { STV090x_P1_MODCODLST2,        0xff },
+       { STV090x_P1_MODCODLST3,        0xff },
+       { STV090x_P1_MODCODLST4,        0xff },
+       { STV090x_P1_MODCODLST5,        0xff },
+       { STV090x_P1_MODCODLST6,        0xff },
+       { STV090x_P1_MODCODLST7,        0xcc },
+       { STV090x_P1_MODCODLST8,        0xcc },
+       { STV090x_P1_MODCODLST9,        0xcc },
+       { STV090x_P1_MODCODLSTA,        0xcc },
+       { STV090x_P1_MODCODLSTB,        0xcc },
+       { STV090x_P1_MODCODLSTC,        0xcc },
+       { STV090x_P1_MODCODLSTD,        0xcc },
+       { STV090x_P1_MODCODLSTE,        0xcc },
+       { STV090x_P1_MODCODLSTF,        0xcf },
+       { STV090x_GENCFG,               0x1d },
+       { STV090x_NBITER_NF4,           0x37 },
+       { STV090x_NBITER_NF5,           0x29 },
+       { STV090x_NBITER_NF6,           0x37 },
+       { STV090x_NBITER_NF7,           0x33 },
+       { STV090x_NBITER_NF8,           0x31 },
+       { STV090x_NBITER_NF9,           0x2f },
+       { STV090x_NBITER_NF10,          0x39 },
+       { STV090x_NBITER_NF11,          0x3a },
+       { STV090x_NBITER_NF12,          0x29 },
+       { STV090x_NBITER_NF13,          0x37 },
+       { STV090x_NBITER_NF14,          0x33 },
+       { STV090x_NBITER_NF15,          0x2f },
+       { STV090x_NBITER_NF16,          0x39 },
+       { STV090x_NBITER_NF17,          0x3a },
+       { STV090x_NBITERNOERR,          0x04 },
+       { STV090x_GAINLLR_NF4,          0x0C },
+       { STV090x_GAINLLR_NF5,          0x0F },
+       { STV090x_GAINLLR_NF6,          0x11 },
+       { STV090x_GAINLLR_NF7,          0x14 },
+       { STV090x_GAINLLR_NF8,          0x17 },
+       { STV090x_GAINLLR_NF9,          0x19 },
+       { STV090x_GAINLLR_NF10,         0x20 },
+       { STV090x_GAINLLR_NF11,         0x21 },
+       { STV090x_GAINLLR_NF12,         0x0D },
+       { STV090x_GAINLLR_NF13,         0x0F },
+       { STV090x_GAINLLR_NF14,         0x13 },
+       { STV090x_GAINLLR_NF15,         0x1A },
+       { STV090x_GAINLLR_NF16,         0x1F },
+       { STV090x_GAINLLR_NF17,         0x21 },
+       { STV090x_RCCFGH,               0x20 },
+       { STV090x_P1_FECM,              0x01 }, /* disable DSS modes */
+       { STV090x_P2_FECM,              0x01 }, /* disable DSS modes */
+       { STV090x_P1_PRVIT,             0x2F }, /* disable PR 6/7 */
+       { STV090x_P2_PRVIT,             0x2F }, /* disable PR 6/7 */
+};
+
+static struct stv090x_reg stv0903_initval[] = {
+       { STV090x_OUTCFG,               0x00 },
+       { STV090x_AGCRF1CFG,            0x11 },
+       { STV090x_STOPCLK1,             0x48 },
+       { STV090x_STOPCLK2,             0x14 },
+       { STV090x_TSTTNR1,              0x27 },
+       { STV090x_TSTTNR2,              0x21 },
+       { STV090x_P1_DISTXCTL,          0x22 },
+       { STV090x_P1_F22TX,             0xc0 },
+       { STV090x_P1_F22RX,             0xc0 },
+       { STV090x_P1_DISRXCTL,          0x00 },
+       { STV090x_P1_DMDCFGMD,          0xF9 },
+       { STV090x_P1_DEMOD,             0x08 },
+       { STV090x_P1_DMDCFG3,           0xc4 },
+       { STV090x_P1_CARFREQ,           0xed },
+       { STV090x_P1_TNRCFG2,           0x82 },
+       { STV090x_P1_LDT,               0xd0 },
+       { STV090x_P1_LDT2,              0xb8 },
+       { STV090x_P1_TMGCFG,            0xd2 },
+       { STV090x_P1_TMGTHRISE,         0x20 },
+       { STV090x_P1_TMGTHFALL,         0x00 },
+       { STV090x_P1_SFRUPRATIO,        0xf0 },
+       { STV090x_P1_SFRLOWRATIO,       0x70 },
+       { STV090x_P1_TSCFGL,            0x20 },
+       { STV090x_P1_FECSPY,            0x88 },
+       { STV090x_P1_FSPYDATA,          0x3a },
+       { STV090x_P1_FBERCPT4,          0x00 },
+       { STV090x_P1_FSPYBER,           0x10 },
+       { STV090x_P1_ERRCTRL1,          0x35 },
+       { STV090x_P1_ERRCTRL2,          0xc1 },
+       { STV090x_P1_CFRICFG,           0xf8 },
+       { STV090x_P1_NOSCFG,            0x1c },
+       { STV090x_P1_DMDTOM,            0x20 },
+       { STV090x_P1_CORRELMANT,        0x70 },
+       { STV090x_P1_CORRELABS,         0x88 },
+       { STV090x_P1_AGC2O,             0x5b },
+       { STV090x_P1_AGC2REF,           0x38 },
+       { STV090x_P1_CARCFG,            0xe4 },
+       { STV090x_P1_ACLC,              0x1A },
+       { STV090x_P1_BCLC,              0x09 },
+       { STV090x_P1_CARHDR,            0x08 },
+       { STV090x_P1_KREFTMG,           0xc1 },
+       { STV090x_P1_SFRSTEP,           0x58 },
+       { STV090x_P1_TMGCFG2,           0x01 },
+       { STV090x_P1_CAR2CFG,           0x26 },
+       { STV090x_P1_BCLC2S2Q,          0x86 },
+       { STV090x_P1_BCLC2S28,          0x86 },
+       { STV090x_P1_SMAPCOEF7,         0x77 },
+       { STV090x_P1_SMAPCOEF6,         0x85 },
+       { STV090x_P1_SMAPCOEF5,         0x77 },
+       { STV090x_P1_DMDCFG2,           0x3b },
+       { STV090x_P1_MODCODLST0,        0xff },
+       { STV090x_P1_MODCODLST1,        0xff },
+       { STV090x_P1_MODCODLST2,        0xff },
+       { STV090x_P1_MODCODLST3,        0xff },
+       { STV090x_P1_MODCODLST4,        0xff },
+       { STV090x_P1_MODCODLST5,        0xff },
+       { STV090x_P1_MODCODLST6,        0xff },
+       { STV090x_P1_MODCODLST7,        0xcc },
+       { STV090x_P1_MODCODLST8,        0xcc },
+       { STV090x_P1_MODCODLST9,        0xcc },
+       { STV090x_P1_MODCODLSTA,        0xcc },
+       { STV090x_P1_MODCODLSTB,        0xcc },
+       { STV090x_P1_MODCODLSTC,        0xcc },
+       { STV090x_P1_MODCODLSTD,        0xcc },
+       { STV090x_P1_MODCODLSTE,        0xcc },
+       { STV090x_P1_MODCODLSTF,        0xcf },
+       { STV090x_GENCFG,               0x1c },
+       { STV090x_NBITER_NF4,           0x37 },
+       { STV090x_NBITER_NF5,           0x29 },
+       { STV090x_NBITER_NF6,           0x37 },
+       { STV090x_NBITER_NF7,           0x33 },
+       { STV090x_NBITER_NF8,           0x31 },
+       { STV090x_NBITER_NF9,           0x2f },
+       { STV090x_NBITER_NF10,          0x39 },
+       { STV090x_NBITER_NF11,          0x3a },
+       { STV090x_NBITER_NF12,          0x29 },
+       { STV090x_NBITER_NF13,          0x37 },
+       { STV090x_NBITER_NF14,          0x33 },
+       { STV090x_NBITER_NF15,          0x2f },
+       { STV090x_NBITER_NF16,          0x39 },
+       { STV090x_NBITER_NF17,          0x3a },
+       { STV090x_NBITERNOERR,          0x04 },
+       { STV090x_GAINLLR_NF4,          0x0C },
+       { STV090x_GAINLLR_NF5,          0x0F },
+       { STV090x_GAINLLR_NF6,          0x11 },
+       { STV090x_GAINLLR_NF7,          0x14 },
+       { STV090x_GAINLLR_NF8,          0x17 },
+       { STV090x_GAINLLR_NF9,          0x19 },
+       { STV090x_GAINLLR_NF10,         0x20 },
+       { STV090x_GAINLLR_NF11,         0x21 },
+       { STV090x_GAINLLR_NF12,         0x0D },
+       { STV090x_GAINLLR_NF13,         0x0F },
+       { STV090x_GAINLLR_NF14,         0x13 },
+       { STV090x_GAINLLR_NF15,         0x1A },
+       { STV090x_GAINLLR_NF16,         0x1F },
+       { STV090x_GAINLLR_NF17,         0x21 },
+       { STV090x_RCCFGH,               0x20 },
+       { STV090x_P1_FECM,              0x01 }, /*disable the DSS mode */
+       { STV090x_P1_PRVIT,             0x2f }  /*disable puncture rate 6/7*/
+};
+
+static struct stv090x_reg stv0900_cut20_val[] = {
+
+       { STV090x_P2_DMDCFG3,           0xe8 },
+       { STV090x_P2_DMDCFG4,           0x10 },
+       { STV090x_P2_CARFREQ,           0x38 },
+       { STV090x_P2_CARHDR,            0x20 },
+       { STV090x_P2_KREFTMG,           0x5a },
+       { STV090x_P2_SMAPCOEF7,         0x06 },
+       { STV090x_P2_SMAPCOEF6,         0x00 },
+       { STV090x_P2_SMAPCOEF5,         0x04 },
+       { STV090x_P2_NOSCFG,            0x0c },
+       { STV090x_P1_DMDCFG3,           0xe8 },
+       { STV090x_P1_DMDCFG4,           0x10 },
+       { STV090x_P1_CARFREQ,           0x38 },
+       { STV090x_P1_CARHDR,            0x20 },
+       { STV090x_P1_KREFTMG,           0x5a },
+       { STV090x_P1_SMAPCOEF7,         0x06 },
+       { STV090x_P1_SMAPCOEF6,         0x00 },
+       { STV090x_P1_SMAPCOEF5,         0x04 },
+       { STV090x_P1_NOSCFG,            0x0c },
+       { STV090x_GAINLLR_NF4,          0x21 },
+       { STV090x_GAINLLR_NF5,          0x21 },
+       { STV090x_GAINLLR_NF6,          0x20 },
+       { STV090x_GAINLLR_NF7,          0x1F },
+       { STV090x_GAINLLR_NF8,          0x1E },
+       { STV090x_GAINLLR_NF9,          0x1E },
+       { STV090x_GAINLLR_NF10,         0x1D },
+       { STV090x_GAINLLR_NF11,         0x1B },
+       { STV090x_GAINLLR_NF12,         0x20 },
+       { STV090x_GAINLLR_NF13,         0x20 },
+       { STV090x_GAINLLR_NF14,         0x20 },
+       { STV090x_GAINLLR_NF15,         0x20 },
+       { STV090x_GAINLLR_NF16,         0x20 },
+       { STV090x_GAINLLR_NF17,         0x21 },
+};
+
+static struct stv090x_reg stv0903_cut20_val[] = {
+       { STV090x_P1_DMDCFG3,           0xe8 },
+       { STV090x_P1_DMDCFG4,           0x10 },
+       { STV090x_P1_CARFREQ,           0x38 },
+       { STV090x_P1_CARHDR,            0x20 },
+       { STV090x_P1_KREFTMG,           0x5a },
+       { STV090x_P1_SMAPCOEF7,         0x06 },
+       { STV090x_P1_SMAPCOEF6,         0x00 },
+       { STV090x_P1_SMAPCOEF5,         0x04 },
+       { STV090x_P1_NOSCFG,            0x0c },
+       { STV090x_GAINLLR_NF4,          0x21 },
+       { STV090x_GAINLLR_NF5,          0x21 },
+       { STV090x_GAINLLR_NF6,          0x20 },
+       { STV090x_GAINLLR_NF7,          0x1F },
+       { STV090x_GAINLLR_NF8,          0x1E },
+       { STV090x_GAINLLR_NF9,          0x1E },
+       { STV090x_GAINLLR_NF10,         0x1D },
+       { STV090x_GAINLLR_NF11,         0x1B },
+       { STV090x_GAINLLR_NF12,         0x20 },
+       { STV090x_GAINLLR_NF13,         0x20 },
+       { STV090x_GAINLLR_NF14,         0x20 },
+       { STV090x_GAINLLR_NF15,         0x20 },
+       { STV090x_GAINLLR_NF16,         0x20 },
+       { STV090x_GAINLLR_NF17,         0x21 }
+};
+
+/* Cut 2.0 Long Frame Tracking CR loop */
+static struct stv090x_long_frame_crloop stv090x_s2_crl_cut20[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_QPSK_12,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x1e },
+       { STV090x_QPSK_35,  0x2f, 0x3f, 0x2e, 0x2f, 0x3d, 0x0f, 0x0e, 0x2e, 0x3d, 0x0e },
+       { STV090x_QPSK_23,  0x2f, 0x3f, 0x2e, 0x2f, 0x0e, 0x0f, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_34,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_45,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_56,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_89,  0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_910, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_8PSK_35,  0x3c, 0x3e, 0x1c, 0x2e, 0x0c, 0x1e, 0x2b, 0x2d, 0x1b, 0x1d },
+       { STV090x_8PSK_23,  0x1d, 0x3e, 0x3c, 0x2e, 0x2c, 0x1e, 0x0c, 0x2d, 0x2b, 0x1d },
+       { STV090x_8PSK_34,  0x0e, 0x3e, 0x3d, 0x2e, 0x0d, 0x1e, 0x2c, 0x2d, 0x0c, 0x1d },
+       { STV090x_8PSK_56,  0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d },
+       { STV090x_8PSK_89,  0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d },
+       { STV090x_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d }
+};
+
+/* Cut 3.0 Long Frame Tracking CR loop */
+static struct stv090x_long_frame_crloop stv090x_s2_crl_cut30[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_QPSK_12,  0x3c, 0x2c, 0x0c, 0x2c, 0x1b, 0x2c, 0x1b, 0x1c, 0x0b, 0x3b },
+       { STV090x_QPSK_35,  0x0d, 0x0d, 0x0c, 0x0d, 0x1b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+       { STV090x_QPSK_23,  0x1d, 0x0d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+       { STV090x_QPSK_34,  0x1d, 0x1d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+       { STV090x_QPSK_45,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+       { STV090x_QPSK_56,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+       { STV090x_QPSK_89,  0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+       { STV090x_QPSK_910, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+       { STV090x_8PSK_35,  0x39, 0x29, 0x39, 0x19, 0x19, 0x19, 0x19, 0x19, 0x09, 0x19 },
+       { STV090x_8PSK_23,  0x2a, 0x39, 0x1a, 0x0a, 0x39, 0x0a, 0x29, 0x39, 0x29, 0x0a },
+       { STV090x_8PSK_34,  0x2b, 0x3a, 0x1b, 0x1b, 0x3a, 0x1b, 0x1a, 0x0b, 0x1a, 0x3a },
+       { STV090x_8PSK_56,  0x0c, 0x1b, 0x3b, 0x3b, 0x1b, 0x3b, 0x3a, 0x3b, 0x3a, 0x1b },
+       { STV090x_8PSK_89,  0x0d, 0x3c, 0x2c, 0x2c, 0x2b, 0x0c, 0x0b, 0x3b, 0x0b, 0x1b },
+       { STV090x_8PSK_910, 0x0d, 0x0d, 0x2c, 0x3c, 0x3b, 0x1c, 0x0b, 0x3b, 0x0b, 0x1b }
+};
+
+/* Cut 2.0 Long Frame Tracking CR Loop */
+static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut20[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_16APSK_23,  0x0c, 0x0c, 0x0c, 0x0c, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x0c },
+       { STV090x_16APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0c, 0x2d, 0x0c, 0x1d, 0x0c },
+       { STV090x_16APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
+       { STV090x_16APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
+       { STV090x_16APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
+       { STV090x_16APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
+       { STV090x_32APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+       { STV090x_32APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+       { STV090x_32APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+       { STV090x_32APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+       { STV090x_32APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }
+};
+
+/* Cut 3.0 Long Frame Tracking CR Loop */
+static struct stv090x_long_frame_crloop        stv090x_s2_apsk_crl_cut30[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_16APSK_23,  0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x0a, 0x3a, 0x0a, 0x2a, 0x0a },
+       { STV090x_16APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x3b, 0x0a, 0x1b, 0x0a },
+       { STV090x_16APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
+       { STV090x_16APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
+       { STV090x_16APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
+       { STV090x_16APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
+       { STV090x_32APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+       { STV090x_32APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+       { STV090x_32APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+       { STV090x_32APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+       { STV090x_32APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }
+};
+
+static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut20[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_QPSK_14,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x2d, 0x1f, 0x3d, 0x3e },
+       { STV090x_QPSK_13,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x3d, 0x0f, 0x3d, 0x2e },
+       { STV090x_QPSK_25,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x2e }
+};
+
+static struct stv090x_long_frame_crloop        stv090x_s2_lowqpsk_crl_cut30[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_QPSK_14,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x2a, 0x1c, 0x3a, 0x3b },
+       { STV090x_QPSK_13,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x3a, 0x0c, 0x3a, 0x2b },
+       { STV090x_QPSK_25,  0x1c, 0x3c, 0x1b, 0x3c, 0x3a, 0x1c, 0x3a, 0x3b, 0x3a, 0x2b }
+};
+
+/* Cut 2.0 Short Frame Tracking CR Loop */
+static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut20[] = {
+       /* MODCOD         2M    5M    10M   20M   30M */
+       { STV090x_QPSK,   0x2f, 0x2e, 0x0e, 0x0e, 0x3d },
+       { STV090x_8PSK,   0x3e, 0x0e, 0x2d, 0x0d, 0x3c },
+       { STV090x_16APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d },
+       { STV090x_32APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d }
+};
+
+/* Cut 3.0 Short Frame Tracking CR Loop */
+static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut30[] = {
+       /* MODCOD         2M    5M    10M   20M   30M */
+       { STV090x_QPSK,   0x2C, 0x2B, 0x0B, 0x0B, 0x3A },
+       { STV090x_8PSK,   0x3B, 0x0B, 0x2A, 0x0A, 0x39 },
+       { STV090x_16APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A },
+       { STV090x_32APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A }
+};
+
+static inline s32 comp2(s32 __x, s32 __width)
+{
+       if (__width == 32)
+               return __x;
+       else
+               return (__x >= (1 << (__width - 1))) ? (__x - (1 << __width)) : __x;
+}
+
+static int stv090x_read_reg(struct stv090x_state *state, unsigned int reg)
+{
+       const struct stv090x_config *config = state->config;
+       int ret;
+
+       u8 b0[] = { reg >> 8, reg & 0xff };
+       u8 buf;
+
+       struct i2c_msg msg[] = {
+               { .addr = config->address, .flags       = 0,            .buf = b0,   .len = 2 },
+               { .addr = config->address, .flags       = I2C_M_RD,     .buf = &buf, .len = 1 }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+       if (ret != 2) {
+               if (ret != -ERESTARTSYS)
+                       dprintk(FE_ERROR, 1,
+                               "Read error, Reg=[0x%02x], Status=%d",
+                               reg, ret);
+
+               return ret < 0 ? ret : -EREMOTEIO;
+       }
+       if (unlikely(*state->verbose >= FE_DEBUGREG))
+               dprintk(FE_ERROR, 1, "Reg=[0x%02x], data=%02x",
+                       reg, buf);
+
+       return (unsigned int) buf;
+}
+
+static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 *data, u32 count)
+{
+       const struct stv090x_config *config = state->config;
+       int ret;
+       u8 buf[2 + count];
+       struct i2c_msg i2c_msg = { .addr = config->address, .flags = 0, .buf = buf, .len = 2 + count };
+
+       buf[0] = reg >> 8;
+       buf[1] = reg & 0xff;
+       memcpy(&buf[2], data, count);
+
+       if (unlikely(*state->verbose >= FE_DEBUGREG)) {
+               int i;
+
+               printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
+               for (i = 0; i < count; i++)
+                       printk(" %02x", data[i]);
+               printk("\n");
+       }
+
+       ret = i2c_transfer(state->i2c, &i2c_msg, 1);
+       if (ret != 1) {
+               if (ret != -ERESTARTSYS)
+                       dprintk(FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d",
+                               reg, data[0], count, ret);
+               return ret < 0 ? ret : -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data)
+{
+       return stv090x_write_regs(state, reg, &data, 1);
+}
+
+static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+
+       reg = STV090x_READ_DEMOD(state, I2CRPT);
+       if (enable) {
+               dprintk(FE_DEBUG, 1, "Enable Gate");
+               STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0)
+                       goto err;
+
+       } else {
+               dprintk(FE_DEBUG, 1, "Disable Gate");
+               STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 0);
+               if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0)
+                       goto err;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static void stv090x_get_lock_tmg(struct stv090x_state *state)
+{
+       switch (state->algo) {
+       case STV090x_BLIND_SEARCH:
+               dprintk(FE_DEBUG, 1, "Blind Search");
+               if (state->srate <= 1500000) {  /*10Msps< SR <=15Msps*/
+                       state->DemodTimeout = 1500;
+                       state->FecTimeout = 400;
+               } else if (state->srate <= 5000000) {  /*10Msps< SR <=15Msps*/
+                       state->DemodTimeout = 1000;
+                       state->FecTimeout = 300;
+               } else {  /*SR >20Msps*/
+                       state->DemodTimeout = 700;
+                       state->FecTimeout = 100;
+               }
+               break;
+
+       case STV090x_COLD_SEARCH:
+       case STV090x_WARM_SEARCH:
+       default:
+               dprintk(FE_DEBUG, 1, "Normal Search");
+               if (state->srate <= 1000000) {  /*SR <=1Msps*/
+                       state->DemodTimeout = 4500;
+                       state->FecTimeout = 1700;
+               } else if (state->srate <= 2000000) { /*1Msps < SR <= 2Msps */
+                       state->DemodTimeout = 2500;
+                       state->FecTimeout = 1100;
+               } else if (state->srate <= 5000000) { /*2Msps < SR <= 5Msps */
+                       state->DemodTimeout = 1000;
+                       state->FecTimeout = 550;
+               } else if (state->srate <= 10000000) { /*5Msps < SR <= 10Msps */
+                       state->DemodTimeout = 700;
+                       state->FecTimeout = 250;
+               } else if (state->srate <= 20000000) { /*10Msps < SR <= 20Msps */
+                       state->DemodTimeout = 400;
+                       state->FecTimeout = 130;
+               } else {   /*SR >20Msps*/
+                       state->DemodTimeout = 300;
+                       state->FecTimeout = 100;
+               }
+               break;
+       }
+
+       if (state->algo == STV090x_WARM_SEARCH)
+               state->DemodTimeout /= 2;
+}
+
+static int stv090x_set_srate(struct stv090x_state *state, u32 srate)
+{
+       u32 sym;
+
+       if (srate > 60000000) {
+               sym  = (srate << 4); /* SR * 2^16 / master_clk */
+               sym /= (state->mclk >> 12);
+       } else if (srate > 6000000) {
+               sym  = (srate << 6);
+               sym /= (state->mclk >> 10);
+       } else {
+               sym  = (srate << 9);
+               sym /= (state->mclk >> 7);
+       }
+
+       if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRINIT0, (sym & 0xff)) < 0) /* LSB */
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate)
+{
+       u32 sym;
+
+       srate = 105 * (srate / 100);
+       if (srate > 60000000) {
+               sym  = (srate << 4); /* SR * 2^16 / master_clk */
+               sym /= (state->mclk >> 12);
+       } else if (srate > 6000000) {
+               sym  = (srate << 6);
+               sym /= (state->mclk >> 10);
+       } else {
+               sym  = (srate << 9);
+               sym /= (state->mclk >> 7);
+       }
+
+       if (sym < 0x7fff) {
+               if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) /* MSB */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) /* LSB */
+                       goto err;
+       } else {
+               if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x7f) < 0) /* MSB */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xff) < 0) /* LSB */
+                       goto err;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate)
+{
+       u32 sym;
+
+       srate = 95 * (srate / 100);
+       if (srate > 60000000) {
+               sym  = (srate << 4); /* SR * 2^16 / master_clk */
+               sym /= (state->mclk >> 12);
+       } else if (srate > 6000000) {
+               sym  = (srate << 6);
+               sym /= (state->mclk >> 10);
+       } else {
+               sym  = (srate << 9);
+               sym /= (state->mclk >> 7);
+       }
+
+       if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0xff)) < 0) /* MSB */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */
+               goto err;
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static u32 stv090x_car_width(u32 srate, enum stv090x_rolloff rolloff)
+{
+       u32 ro;
+
+       switch (rolloff) {
+       case STV090x_RO_20:
+               ro = 20;
+               break;
+       case STV090x_RO_25:
+               ro = 25;
+               break;
+       case STV090x_RO_35:
+       default:
+               ro = 35;
+               break;
+       }
+
+       return srate + (srate * ro) / 100;
+}
+
+static int stv090x_set_vit_thacq(struct stv090x_state *state)
+{
+       if (STV090x_WRITE_DEMOD(state, VTH12, 0x96) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH23, 0x64) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH34, 0x36) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH56, 0x23) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH67, 0x1e) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH78, 0x19) < 0)
+               goto err;
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_vit_thtracq(struct stv090x_state *state)
+{
+       if (STV090x_WRITE_DEMOD(state, VTH12, 0xd0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH23, 0x7d) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH34, 0x53) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH56, 0x2f) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH67, 0x24) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH78, 0x1f) < 0)
+               goto err;
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_viterbi(struct stv090x_state *state)
+{
+       switch (state->search_mode) {
+       case STV090x_SEARCH_AUTO:
+               if (STV090x_WRITE_DEMOD(state, FECM, 0x10) < 0) /* DVB-S and DVB-S2 */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, PRVIT, 0x3f) < 0) /* all puncture rate */
+                       goto err;
+               break;
+       case STV090x_SEARCH_DVBS1:
+               if (STV090x_WRITE_DEMOD(state, FECM, 0x00) < 0) /* disable DSS */
+                       goto err;
+               switch (state->fec) {
+               case STV090x_PR12:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR23:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR34:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x04) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR56:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x08) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR78:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x20) < 0)
+                               goto err;
+                       break;
+
+               default:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x2f) < 0) /* all */
+                               goto err;
+                       break;
+               }
+               break;
+       case STV090x_SEARCH_DSS:
+               if (STV090x_WRITE_DEMOD(state, FECM, 0x80) < 0)
+                       goto err;
+               switch (state->fec) {
+               case STV090x_PR12:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR23:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR67:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x10) < 0)
+                               goto err;
+                       break;
+
+               default:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x13) < 0) /* 1/2, 2/3, 6/7 */
+                               goto err;
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_stop_modcod(struct stv090x_state *state)
+{
+       if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xff) < 0)
+               goto err;
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_activate_modcod(struct stv090x_state *state)
+{
+       if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xfc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_activate_modcod_single(struct stv090x_state *state)
+{
+
+       if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xf0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0x0f) < 0)
+               goto err;
+
+       return 0;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable)
+{
+       u32 reg;
+
+       switch (state->demod) {
+       case STV090x_DEMODULATOR_0:
+               mutex_lock(&demod_lock);
+               reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+               STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable);
+               if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+                       goto err;
+               mutex_unlock(&demod_lock);
+               break;
+
+       case STV090x_DEMODULATOR_1:
+               mutex_lock(&demod_lock);
+               reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+               STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable);
+               if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+                       goto err;
+               mutex_unlock(&demod_lock);
+               break;
+
+       default:
+               dprintk(FE_ERROR, 1, "Wrong demodulator!");
+               break;
+       }
+       return 0;
+err:
+       mutex_unlock(&demod_lock);
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_dvbs_track_crl(struct stv090x_state *state)
+{
+       if (state->dev_ver >= 0x30) {
+               /* Set ACLC BCLC optimised value vs SR */
+               if (state->srate >= 15000000) {
+                       if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, BCLC, 0x1a) < 0)
+                               goto err;
+               } else if ((state->srate >= 7000000) && (15000000 > state->srate)) {
+                       if (STV090x_WRITE_DEMOD(state, ACLC, 0x0c) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, BCLC, 0x1b) < 0)
+                               goto err;
+               } else if (state->srate < 7000000) {
+                       if (STV090x_WRITE_DEMOD(state, ACLC, 0x2c) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, BCLC, 0x1c) < 0)
+                               goto err;
+               }
+
+       } else {
+               /* Cut 2.0 */
+               if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
+                       goto err;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_delivery_search(struct stv090x_state *state)
+{
+       u32 reg;
+
+       switch (state->search_mode) {
+       case STV090x_SEARCH_DVBS1:
+       case STV090x_SEARCH_DSS:
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+
+               /* Activate Viterbi decoder in legacy search,
+                * do not use FRESVIT1, might impact VITERBI2
+                */
+               if (stv090x_vitclk_ctl(state, 0) < 0)
+                       goto err;
+
+               if (stv090x_dvbs_track_crl(state) < 0)
+                       goto err;
+
+               if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x22) < 0) /* disable DVB-S2 */
+                       goto err;
+
+               if (stv090x_set_vit_thacq(state) < 0)
+                       goto err;
+               if (stv090x_set_viterbi(state) < 0)
+                       goto err;
+               break;
+
+       case STV090x_SEARCH_DVBS2:
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+
+               if (stv090x_vitclk_ctl(state, 1) < 0)
+                       goto err;
+
+               if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) /* stop DVB-S CR loop */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
+                       goto err;
+
+               if (state->dev_ver <= 0x20) {
+                       /* enable S2 carrier loop */
+                       if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
+                               goto err;
+               } else {
+                       /* > Cut 3: Stop carrier 3 */
+                       if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
+                               goto err;
+               }
+
+               if (state->demod_mode != STV090x_SINGLE) {
+                       /* Cut 2: enable link during search */
+                       if (stv090x_activate_modcod(state) < 0)
+                               goto err;
+               } else {
+                       /* Single demodulator
+                        * Authorize SHORT and LONG frames,
+                        * QPSK, 8PSK, 16APSK and 32APSK
+                        */
+                       if (stv090x_activate_modcod_single(state) < 0)
+                               goto err;
+               }
+
+               break;
+
+       case STV090x_SEARCH_AUTO:
+       default:
+               /* enable DVB-S2 and DVB-S2 in Auto MODE */
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+
+               if (stv090x_vitclk_ctl(state, 0) < 0)
+                       goto err;
+
+               if (stv090x_dvbs_track_crl(state) < 0)
+                       goto err;
+
+               if (state->dev_ver <= 0x20) {
+                       /* enable S2 carrier loop */
+                       if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
+                               goto err;
+               } else {
+                       /* > Cut 3: Stop carrier 3 */
+                       if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
+                               goto err;
+               }
+
+               if (state->demod_mode != STV090x_SINGLE) {
+                       /* Cut 2: enable link during search */
+                       if (stv090x_activate_modcod(state) < 0)
+                               goto err;
+               } else {
+                       /* Single demodulator
+                        * Authorize SHORT and LONG frames,
+                        * QPSK, 8PSK, 16APSK and 32APSK
+                        */
+                       if (stv090x_activate_modcod_single(state) < 0)
+                               goto err;
+               }
+
+               if (state->srate >= 2000000) {
+                       /* Srate >= 2MSPS, Viterbi threshold to acquire */
+                       if (stv090x_set_vit_thacq(state) < 0)
+                               goto err;
+               } else {
+                       /* Srate < 2MSPS, Reset Viterbi thresholdto track
+                        * and then re-acquire
+                        */
+                       if (stv090x_set_vit_thtracq(state) < 0)
+                               goto err;
+               }
+
+               if (stv090x_set_viterbi(state) < 0)
+                       goto err;
+               break;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_start_search(struct stv090x_state *state)
+{
+       u32 reg, freq_abs;
+       s16 freq;
+
+       /* Reset demodulator */
+       reg = STV090x_READ_DEMOD(state, DMDISTATE);
+       STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f);
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+               goto err;
+
+       if (state->dev_ver <= 0x20) {
+               if (state->srate <= 5000000) {
+                       if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRUP1, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRLOW0, 0x00) < 0)
+                               goto err;
+
+                       /*enlarge the timing bandwith for Low SR*/
+                       if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0)
+                               goto err;
+               } else {
+                       /* If the symbol rate is >5 Msps
+                       Set The carrier search up and low to auto mode */
+                       if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
+                               goto err;
+                       /*reduce the timing bandwith for high SR*/
+                       if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
+                               goto err;
+               }
+       } else {
+               /* >= Cut 3 */
+               if (state->srate <= 5000000) {
+                       /* enlarge the timing bandwith for Low SR */
+                       STV090x_WRITE_DEMOD(state, RTCS2, 0x68);
+               } else {
+                       /* reduce timing bandwith for high SR */
+                       STV090x_WRITE_DEMOD(state, RTCS2, 0x44);
+               }
+
+               /* Set CFR min and max to manual mode */
+               STV090x_WRITE_DEMOD(state, CARCFG, 0x46);
+
+               if (state->algo == STV090x_WARM_SEARCH) {
+                       /* WARM Start
+                        * CFR min = -1MHz,
+                        * CFR max = +1MHz
+                        */
+                       freq_abs  = 1000 << 16;
+                       freq_abs /= (state->mclk / 1000);
+                       freq      = (s16) freq_abs;
+               } else {
+                       /* COLD Start
+                        * CFR min =- (SearchRange / 2 + 600KHz)
+                        * CFR max = +(SearchRange / 2 + 600KHz)
+                        * (600KHz for the tuner step size)
+                        */
+                       freq_abs  = (state->search_range / 2000) + 600;
+                       freq_abs  = freq_abs << 16;
+                       freq_abs /= (state->mclk / 1000);
+                       freq      = (s16) freq_abs;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRUP1, LSB(freq)) < 0)
+                       goto err;
+
+               freq *= -1;
+
+               if (STV090x_WRITE_DEMOD(state, CFRLOW1, MSB(freq)) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRLOW0, LSB(freq)) < 0)
+                       goto err;
+
+       }
+
+       if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0)
+               goto err;
+
+       if (state->dev_ver >= 0x20) {
+               if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
+                       goto err;
+
+               if ((state->search_mode == STV090x_DVBS1)       ||
+                       (state->search_mode == STV090x_DSS)     ||
+                       (state->search_mode == STV090x_SEARCH_AUTO)) {
+
+                       if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0)
+                               goto err;
+               }
+       }
+
+       if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xe0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xc0) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+       STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0);
+       STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+               goto err;
+       reg = STV090x_READ_DEMOD(state, DMDCFG2);
+       STV090x_SETFIELD_Px(reg, S1S2_SEQUENTIAL_FIELD, 0x0);
+       if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0)
+               goto err;
+
+       if (state->dev_ver >= 0x20) {
+               /*Frequency offset detector setting*/
+               if (state->srate < 2000000) {
+                       if (state->dev_ver <= 0x20) {
+                               /* Cut 2 */
+                               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0)
+                                       goto err;
+                       } else {
+                               /* Cut 2 */
+                               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0)
+                                       goto err;
+                       }
+                       if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0)
+                               goto err;
+               }
+
+               if (state->srate < 10000000) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0)
+                               goto err;
+               } else {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0)
+                               goto err;
+               }
+       } else {
+               if (state->srate < 10000000) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xef) < 0)
+                               goto err;
+               } else {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xed) < 0)
+                               goto err;
+               }
+       }
+
+       switch (state->algo) {
+       case STV090x_WARM_SEARCH:
+               /* The symbol rate and the exact
+                * carrier Frequency are known
+                */
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+                       goto err;
+               break;
+
+       case STV090x_COLD_SEARCH:
+               /* The symbol rate is known */
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+                       goto err;
+               break;
+
+       default:
+               break;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_agc2_min_level(struct stv090x_state *state)
+{
+       u32 agc2_min = 0, agc2 = 0, freq_init, freq_step, reg;
+       s32 i, j, steps, dir;
+
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+               goto err;
+       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+       STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
+       STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) /* SR = 65 Msps Max */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) /* SR= 400 ksps Min */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) /* stop acq @ coarse carrier state */
+               goto err;
+       if (stv090x_set_srate(state, 1000000) < 0)
+               goto err;
+
+       steps  = -1 + state->search_range / 1000000;
+       steps /= 2;
+       steps  = (2 * steps) + 1;
+       if (steps < 0)
+               steps = 1;
+
+       dir = 1;
+       freq_step = (1000000 * 256) / (state->mclk / 256);
+       freq_init = 0;
+
+       for (i = 0; i < steps; i++) {
+               if (dir > 0)
+                       freq_init = freq_init + (freq_step * i);
+               else
+                       freq_init = freq_init - (freq_step * i);
+
+               dir = -1;
+
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_init >> 8) & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_init & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */
+                       goto err;
+               msleep(10);
+               for (j = 0; j < 10; j++) {
+                       agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
+                       agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+               }
+               agc2 /= 10;
+               agc2_min = 0xffff;
+               if (agc2 < 0xffff)
+                       agc2_min = agc2;
+       }
+
+       return agc2_min;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static u32 stv090x_get_srate(struct stv090x_state *state, u32 clk)
+{
+       u8 r3, r2, r1, r0;
+       s32 srate, int_1, int_2, tmp_1, tmp_2;
+
+       r3 = STV090x_READ_DEMOD(state, SFR3);
+       r2 = STV090x_READ_DEMOD(state, SFR2);
+       r1 = STV090x_READ_DEMOD(state, SFR1);
+       r0 = STV090x_READ_DEMOD(state, SFR0);
+
+       srate = ((r3 << 24) | (r2 << 16) | (r1 <<  8) | r0);
+
+       int_1 = clk >> 16;
+       int_2 = srate >> 16;
+
+       tmp_1 = clk % 0x10000;
+       tmp_2 = srate % 0x10000;
+
+       srate = (int_1 * int_2) +
+               ((int_1 * tmp_2) >> 16) +
+               ((int_2 * tmp_1) >> 16);
+
+       return srate;
+}
+
+static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
+{
+       struct dvb_frontend *fe = &state->frontend;
+
+       int tmg_lock = 0, i;
+       s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq;
+       u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg;
+
+       reg = STV090x_READ_DEMOD(state, DMDISTATE);
+       STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0)
+               goto err;
+       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+       STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
+       STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x60) < 0)
+               goto err;
+
+       if (state->dev_ver >= 0x30) {
+               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
+                       goto err;
+
+       } else if (state->dev_ver >= 0x20) {
+               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
+                       goto err;
+       }
+
+       if (state->srate <= 2000000)
+               car_step = 1000;
+       else if (state->srate <= 5000000)
+               car_step = 2000;
+       else if (state->srate <= 12000000)
+               car_step = 3000;
+       else
+               car_step = 5000;
+
+       steps  = -1 + ((state->search_range / 1000) / car_step);
+       steps /= 2;
+       steps  = (2 * steps) + 1;
+       if (steps < 0)
+               steps = 1;
+       else if (steps > 10) {
+               steps = 11;
+               car_step = (state->search_range / 1000) / 10;
+       }
+       cur_step = 0;
+       dir = 1;
+       freq = state->frequency;
+
+       while ((!tmg_lock) && (cur_step < steps)) {
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */
+                       goto err;
+               reg = STV090x_READ_DEMOD(state, DMDISTATE);
+               STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x00); /* trigger acquisition */
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+                       goto err;
+               msleep(50);
+               for (i = 0; i < 10; i++) {
+                       reg = STV090x_READ_DEMOD(state, DSTATUS);
+                       if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
+                               tmg_cpt++;
+                       agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
+                       agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+               }
+               agc2 /= 10;
+               srate_coarse = stv090x_get_srate(state, state->mclk);
+               cur_step++;
+               dir *= -1;
+               if ((tmg_cpt >= 5) && (agc2 < 0x1f00) && (srate_coarse < 55000000) && (srate_coarse > 850000))
+                       tmg_lock = 1;
+               else if (cur_step < steps) {
+                       if (dir > 0)
+                               freq += cur_step * car_step;
+                       else
+                               freq -= cur_step * car_step;
+
+                       /* Setup tuner */
+                       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                               goto err;
+
+                       if (state->config->tuner_set_frequency) {
+                               if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+                                       goto err;
+                       }
+
+                       if (state->config->tuner_set_bandwidth) {
+                               if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+                                       goto err;
+                       }
+
+                       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                               goto err;
+
+                       msleep(50);
+
+                       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                               goto err;
+
+                       if (state->config->tuner_get_status) {
+                               if (state->config->tuner_get_status(fe, &reg) < 0)
+                                       goto err;
+                       }
+
+                       if (reg)
+                               dprintk(FE_DEBUG, 1, "Tuner phase locked");
+                       else
+                               dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+                       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                               goto err;
+
+               }
+       }
+       if (!tmg_lock)
+               srate_coarse = 0;
+       else
+               srate_coarse = stv090x_get_srate(state, state->mclk);
+
+       return srate_coarse;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
+{
+       u32 srate_coarse, freq_coarse, sym, reg;
+
+       srate_coarse = stv090x_get_srate(state, state->mclk);
+       freq_coarse  = STV090x_READ_DEMOD(state, CFR2) << 8;
+       freq_coarse |= STV090x_READ_DEMOD(state, CFR1);
+       sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+
+       if (sym < state->srate)
+               srate_coarse = 0;
+       else {
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0x01) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
+                       goto err;
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+
+               if (state->dev_ver >= 0x30) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0)
+                               goto err;
+               } else if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+                               goto err;
+               }
+
+               if (srate_coarse > 3000000) {
+                       sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+                       sym  = (sym / 1000) * 65536;
+                       sym /= (state->mclk / 1000);
+                       if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
+                               goto err;
+                       sym  = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */
+                       sym  = (sym / 1000) * 65536;
+                       sym /= (state->mclk / 1000);
+                       if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
+                               goto err;
+                       sym  = (srate_coarse / 1000) * 65536;
+                       sym /= (state->mclk / 1000);
+                       if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
+                               goto err;
+               } else {
+                       sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+                       sym  = (sym / 100) * 65536;
+                       sym /= (state->mclk / 100);
+                       if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
+                               goto err;
+                       sym  = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */
+                       sym  = (sym / 100) * 65536;
+                       sym /= (state->mclk / 100);
+                       if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
+                               goto err;
+                       sym  = (srate_coarse / 100) * 65536;
+                       sym /= (state->mclk / 100);
+                       if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
+                               goto err;
+               }
+               if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_coarse >> 8) & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_coarse & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) /* trigger acquisition */
+                       goto err;
+       }
+
+       return srate_coarse;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout)
+{
+       s32 timer = 0, lock = 0;
+       u32 reg;
+       u8 stat;
+
+       while ((timer < timeout) && (!lock)) {
+               reg = STV090x_READ_DEMOD(state, DMDSTATE);
+               stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+               switch (stat) {
+               case 0: /* searching */
+               case 1: /* first PLH detected */
+               default:
+                       dprintk(FE_DEBUG, 1, "Demodulator searching ..");
+                       lock = 0;
+                       break;
+               case 2: /* DVB-S2 mode */
+               case 3: /* DVB-S1/legacy mode */
+                       reg = STV090x_READ_DEMOD(state, DSTATUS);
+                       lock = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+                       break;
+               }
+
+               if (!lock)
+                       msleep(10);
+               else
+                       dprintk(FE_DEBUG, 1, "Demodulator acquired LOCK");
+
+               timer += 10;
+       }
+       return lock;
+}
+
+static int stv090x_blind_search(struct stv090x_state *state)
+{
+       u32 agc2, reg, srate_coarse;
+       s32 timeout_dmd = 500, cpt_fail, agc2_ovflw, i;
+       u8 k_ref, k_max, k_min;
+       int coarse_fail, lock;
+
+       k_max = 120;
+       k_min = 30;
+
+       agc2 = stv090x_get_agc2_min_level(state);
+
+       if (agc2 > STV090x_SEARCH_AGC2_TH(state->dev_ver)) {
+               lock = 0;
+       } else {
+
+               if (state->dev_ver <= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
+                               goto err;
+               } else {
+                       /* > Cut 3 */
+                       if (STV090x_WRITE_DEMOD(state, CARCFG, 0x06) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
+                       goto err;
+
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) /* set viterbi hysteresis */
+                               goto err;
+               }
+
+               k_ref = k_max;
+               do {
+                       if (STV090x_WRITE_DEMOD(state, KREFTMG, k_ref) < 0)
+                               goto err;
+                       if (stv090x_srate_srch_coarse(state) != 0) {
+                               srate_coarse = stv090x_srate_srch_fine(state);
+                               if (srate_coarse != 0) {
+                                       stv090x_get_lock_tmg(state);
+                                       lock = stv090x_get_dmdlock(state, timeout_dmd);
+                               } else {
+                                       lock = 0;
+                               }
+                       } else {
+                               cpt_fail = 0;
+                               agc2_ovflw = 0;
+                               for (i = 0; i < 10; i++) {
+                                       agc2  = STV090x_READ_DEMOD(state, AGC2I1) << 8;
+                                       agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+                                       if (agc2 >= 0xff00)
+                                               agc2_ovflw++;
+                                       reg = STV090x_READ_DEMOD(state, DSTATUS2);
+                                       if ((STV090x_GETFIELD_Px(reg, CFR_OVERFLOW_FIELD) == 0x01) &&
+                                           (STV090x_GETFIELD_Px(reg, DEMOD_DELOCK_FIELD) == 0x01))
+
+                                               cpt_fail++;
+                               }
+                               if ((cpt_fail > 7) || (agc2_ovflw > 7))
+                                       coarse_fail = 1;
+
+                               lock = 0;
+                       }
+                       k_ref -= 30;
+               } while ((k_ref >= k_min) && (!lock) && (!coarse_fail));
+       }
+
+       return lock;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_chk_tmg(struct stv090x_state *state)
+{
+       u32 reg;
+       s32 tmg_cpt = 0, i;
+       u8 freq, tmg_thh, tmg_thl;
+       int tmg_lock;
+
+       freq = STV090x_READ_DEMOD(state, CARFREQ);
+       tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE);
+       tmg_thl = STV090x_READ_DEMOD(state, TMGTHFALL);
+       if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+       STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); /* stop carrier offset search */
+       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, RTC, 0x80) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, RTCS2, 0x40) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x00) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) /* set car ofset to 0 */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x65) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) /* trigger acquisition */
+               goto err;
+       msleep(10);
+
+       for (i = 0; i < 10; i++) {
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
+                       tmg_cpt++;
+               msleep(1);
+       }
+       if (tmg_cpt >= 3)
+               tmg_lock = 1;
+
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) /* DVB-S1 timing */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) /* DVB-S2 timing */
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, CARFREQ, freq) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHRISE, tmg_thh) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHFALL, tmg_thl) < 0)
+               goto err;
+
+       return  tmg_lock;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
+{
+       struct dvb_frontend *fe = &state->frontend;
+
+       u32 reg;
+       s32 car_step, steps, cur_step, dir, freq, timeout_lock;
+       int lock = 0;
+
+       if (state->srate >= 10000000)
+               timeout_lock = timeout_dmd / 3;
+       else
+               timeout_lock = timeout_dmd / 2;
+
+       lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */
+       if (!lock) {
+               if (state->srate >= 10000000) {
+                       if (stv090x_chk_tmg(state)) {
+                               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+                                       goto err;
+                               lock = stv090x_get_dmdlock(state, timeout_dmd);
+                       } else {
+                               lock = 0;
+                       }
+               } else {
+                       if (state->srate <= 4000000)
+                               car_step = 1000;
+                       else if (state->srate <= 7000000)
+                               car_step = 2000;
+                       else if (state->srate <= 10000000)
+                               car_step = 3000;
+                       else
+                               car_step = 5000;
+
+                       steps  = (state->search_range / 1000) / car_step;
+                       steps /= 2;
+                       steps  = 2 * (steps + 1);
+                       if (steps < 0)
+                               steps = 2;
+                       else if (steps > 12)
+                               steps = 12;
+
+                       cur_step = 1;
+                       dir = 1;
+
+                       if (!lock) {
+                               freq = state->frequency;
+                               state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate;
+                               while ((cur_step <= steps) && (!lock)) {
+                                       if (dir > 0)
+                                               freq += cur_step * car_step;
+                                       else
+                                               freq -= cur_step * car_step;
+
+                                       /* Setup tuner */
+                                       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                                               goto err;
+
+                                       if (state->config->tuner_set_frequency) {
+                                               if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+                                                       goto err;
+                                       }
+
+                                       if (state->config->tuner_set_bandwidth) {
+                                               if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+                                                       goto err;
+                                       }
+
+                                       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                                               goto err;
+
+                                       msleep(50);
+
+                                       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                                               goto err;
+
+                                       if (state->config->tuner_get_status) {
+                                               if (state->config->tuner_get_status(fe, &reg) < 0)
+                                                       goto err;
+                                       }
+
+                                       if (reg)
+                                               dprintk(FE_DEBUG, 1, "Tuner phase locked");
+                                       else
+                                               dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+                                       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                                               goto err;
+
+                                       STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
+                                       if (state->delsys == STV090x_DVBS2) {
+                                               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+                                               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+                                               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+                                               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                                                       goto err;
+                                               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+                                               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+                                               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                                                       goto err;
+                                       }
+                                       if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+                                               goto err;
+                                       lock = stv090x_get_dmdlock(state, (timeout_dmd / 3));
+
+                                       dir *= -1;
+                                       cur_step++;
+                               }
+                       }
+               }
+       }
+
+       return lock;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s32 *timeout_sw, s32 *steps)
+{
+       s32 timeout, inc, steps_max, srate, car_max;
+
+       srate = state->srate;
+       car_max = state->search_range / 1000;
+       car_max += car_max / 10;
+       car_max  = 65536 * (car_max / 2);
+       car_max /= (state->mclk / 1000);
+
+       if (car_max > 0x4000)
+               car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */
+
+       inc  = srate;
+       inc /= state->mclk / 1000;
+       inc *= 256;
+       inc *= 256;
+       inc /= 1000;
+
+       switch (state->search_mode) {
+       case STV090x_SEARCH_DVBS1:
+       case STV090x_SEARCH_DSS:
+               inc *= 3; /* freq step = 3% of srate */
+               timeout = 20;
+               break;
+
+       case STV090x_SEARCH_DVBS2:
+               inc *= 4;
+               timeout = 25;
+               break;
+
+       case STV090x_SEARCH_AUTO:
+       default:
+               inc *= 3;
+               timeout = 25;
+               break;
+       }
+       inc /= 100;
+       if ((inc > car_max) || (inc < 0))
+               inc = car_max / 2; /* increment <= 1/8 Mclk */
+
+       timeout *= 27500; /* 27.5 Msps reference */
+       if (srate > 0)
+               timeout /= (srate / 1000);
+
+       if ((timeout > 100) || (timeout < 0))
+               timeout = 100;
+
+       steps_max = (car_max / inc) + 1; /* min steps = 3 */
+       if ((steps_max > 100) || (steps_max < 0)) {
+               steps_max = 100; /* max steps <= 100 */
+               inc = car_max / steps_max;
+       }
+       *freq_inc = inc;
+       *timeout_sw = timeout;
+       *steps = steps_max;
+
+       return 0;
+}
+
+static int stv090x_chk_signal(struct stv090x_state *state)
+{
+       s32 offst_car, agc2, car_max;
+       int no_signal;
+
+       offst_car  = STV090x_READ_DEMOD(state, CFR2) << 8;
+       offst_car |= STV090x_READ_DEMOD(state, CFR1);
+       offst_car = comp2(offst_car, 16);
+
+       agc2  = STV090x_READ_DEMOD(state, AGC2I1) << 8;
+       agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+       car_max = state->search_range / 1000;
+
+       car_max += (car_max / 10); /* 10% margin */
+       car_max  = (65536 * car_max / 2);
+       car_max /= state->mclk / 1000;
+
+       if (car_max > 0x4000)
+               car_max = 0x4000;
+
+       if ((agc2 > 0x2000) || (offst_car > 2 * car_max) || (offst_car < -2 * car_max)) {
+               no_signal = 1;
+               dprintk(FE_DEBUG, 1, "No Signal");
+       } else {
+               no_signal = 0;
+               dprintk(FE_DEBUG, 1, "Found Signal");
+       }
+
+       return no_signal;
+}
+
+static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 timeout, int zigzag, s32 steps_max)
+{
+       int no_signal, lock = 0;
+       s32 cpt_step = 0, offst_freq, car_max;
+       u32 reg;
+
+       car_max  = state->search_range / 1000;
+       car_max += (car_max / 10);
+       car_max  = (65536 * car_max / 2);
+       car_max /= (state->mclk / 1000);
+       if (car_max > 0x4000)
+               car_max = 0x4000;
+
+       if (zigzag)
+               offst_freq = 0;
+       else
+               offst_freq = -car_max + inc;
+
+       do {
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT1, ((offst_freq / 256) & 0xff)) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT0, offst_freq & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+                       goto err;
+
+               reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+               STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x1); /* stop DVB-S2 packet delin */
+               if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+                       goto err;
+
+               if (zigzag) {
+                       if (offst_freq >= 0)
+                               offst_freq = -offst_freq - 2 * inc;
+                       else
+                               offst_freq = -offst_freq;
+               } else {
+                       offst_freq += 2 * inc;
+               }
+
+               cpt_step++;
+
+               lock = stv090x_get_dmdlock(state, timeout);
+               no_signal = stv090x_chk_signal(state);
+
+       } while ((!lock) &&
+                (!no_signal) &&
+                 ((offst_freq - inc) < car_max) &&
+                 ((offst_freq + inc) > -car_max) &&
+                 (cpt_step < steps_max));
+
+       reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+       STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+                       goto err;
+
+       return lock;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_sw_algo(struct stv090x_state *state)
+{
+       int no_signal, zigzag, lock = 0;
+       u32 reg;
+
+       s32 dvbs2_fly_wheel;
+       s32 inc, timeout_step, trials, steps_max;
+
+       /* get params */
+       stv090x_get_loop_params(state, &inc, &timeout_step, &steps_max);
+
+       switch (state->search_mode) {
+       case STV090x_SEARCH_DVBS1:
+       case STV090x_SEARCH_DSS:
+               /* accelerate the frequency detector */
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x49) < 0)
+                       goto err;
+               zigzag = 0;
+               break;
+
+       case STV090x_SEARCH_DVBS2:
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
+                       goto err;
+               zigzag = 1;
+               break;
+
+       case STV090x_SEARCH_AUTO:
+       default:
+               /* accelerate the frequency detector */
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0xc9) < 0)
+                       goto err;
+               zigzag = 0;
+               break;
+       }
+
+       trials = 0;
+       do {
+               lock = stv090x_search_car_loop(state, inc, timeout_step, zigzag, steps_max);
+               no_signal = stv090x_chk_signal(state);
+               trials++;
+
+               /*run the SW search 2 times maximum*/
+               if (lock || no_signal || (trials == 2)) {
+                       /*Check if the demod is not losing lock in DVBS2*/
+                       if (state->dev_ver >= 0x20) {
+                               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
+                                       goto err;
+                       }
+
+                       reg = STV090x_READ_DEMOD(state, DMDSTATE);
+                       if ((lock) && (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == STV090x_DVBS2)) {
+                               /*Check if the demod is not losing lock in DVBS2*/
+                               msleep(timeout_step);
+                               reg = STV090x_READ_DEMOD(state, DMDFLYW);
+                               dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
+                               if (dvbs2_fly_wheel < 0xd) {     /*if correct frames is decrementing */
+                                       msleep(timeout_step);
+                                       reg = STV090x_READ_DEMOD(state, DMDFLYW);
+                                       dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
+                               }
+                               if (dvbs2_fly_wheel < 0xd) {
+                                       /*FALSE lock, The demod is loosing lock */
+                                       lock = 0;
+                                       if (trials < 2) {
+                                               if (state->dev_ver >= 0x20) {
+                                                       if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+                                                               goto err;
+                                               }
+
+                                               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
+                                                       goto err;
+                                       }
+                               }
+                       }
+               }
+       } while ((!lock) && (trials < 2) && (!no_signal));
+
+       return lock;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static enum stv090x_delsys stv090x_get_std(struct stv090x_state *state)
+{
+       u32 reg;
+       enum stv090x_delsys delsys;
+
+       reg = STV090x_READ_DEMOD(state, DMDSTATE);
+       if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 2)
+               delsys = STV090x_DVBS2;
+       else if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 3) {
+               reg = STV090x_READ_DEMOD(state, FECM);
+               if (STV090x_GETFIELD_Px(reg, DSS_DVB_FIELD) == 1)
+                       delsys = STV090x_DSS;
+               else
+                       delsys = STV090x_DVBS1;
+       } else {
+               delsys = STV090x_ERROR;
+       }
+
+       return delsys;
+}
+
+/* in Hz */
+static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk)
+{
+       s32 derot, int_1, int_2, tmp_1, tmp_2;
+
+       derot  = STV090x_READ_DEMOD(state, CFR2) << 16;
+       derot |= STV090x_READ_DEMOD(state, CFR1) <<  8;
+       derot |= STV090x_READ_DEMOD(state, CFR0);
+
+       derot = comp2(derot, 24);
+       int_1 = state->mclk >> 12;
+       int_2 = derot >> 12;
+
+       /* carrier_frequency = MasterClock * Reg / 2^24 */
+       tmp_1 = state->mclk % 0x1000;
+       tmp_2 = derot % 0x1000;
+
+       derot = (int_1 * int_2) +
+               ((int_1 * tmp_2) >> 12) +
+               ((int_1 * tmp_1) >> 12);
+
+       return derot;
+}
+
+static int stv090x_get_viterbi(struct stv090x_state *state)
+{
+       u32 reg, rate;
+
+       reg = STV090x_READ_DEMOD(state, VITCURPUN);
+       rate = STV090x_GETFIELD_Px(reg, VIT_CURPUN_FIELD);
+
+       switch (rate) {
+       case 13:
+               state->fec = STV090x_PR12;
+               break;
+
+       case 18:
+               state->fec = STV090x_PR23;
+               break;
+
+       case 21:
+               state->fec = STV090x_PR34;
+               break;
+
+       case 24:
+               state->fec = STV090x_PR56;
+               break;
+
+       case 25:
+               state->fec = STV090x_PR67;
+               break;
+
+       case 26:
+               state->fec = STV090x_PR78;
+               break;
+
+       default:
+               state->fec = STV090x_PRERR;
+               break;
+       }
+
+       return 0;
+}
+
+static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *state)
+{
+       struct dvb_frontend *fe = &state->frontend;
+
+       u8 tmg;
+       u32 reg;
+       s32 i = 0, offst_freq;
+
+       msleep(5);
+
+       if (state->algo == STV090x_BLIND_SEARCH) {
+               tmg = STV090x_READ_DEMOD(state, TMGREG2);
+               STV090x_WRITE_DEMOD(state, SFRSTEP, 0x5c);
+               while ((i <= 50) && (tmg != 0) && (tmg != 0xff)) {
+                       tmg = STV090x_READ_DEMOD(state, TMGREG2);
+                       msleep(5);
+                       i += 5;
+               }
+       }
+       state->delsys = stv090x_get_std(state);
+
+       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+               goto err;
+
+       if (state->config->tuner_get_frequency) {
+               if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
+                       goto err;
+       }
+
+       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+               goto err;
+
+       offst_freq = stv090x_get_car_freq(state, state->mclk) / 1000;
+       state->frequency += offst_freq;
+
+       if (stv090x_get_viterbi(state) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, DMDMODCOD);
+       state->modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
+       state->pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
+       state->frame_len = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) >> 1;
+       reg = STV090x_READ_DEMOD(state, TMGOBS);
+       state->rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
+       reg = STV090x_READ_DEMOD(state, FECM);
+       state->inversion = STV090x_GETFIELD_Px(reg, IQINV_FIELD);
+
+       if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) {
+
+               if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                       goto err;
+
+               if (state->config->tuner_get_frequency) {
+                       if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
+                               goto err;
+               }
+
+               if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                       goto err;
+
+               if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
+                       return STV090x_RANGEOK;
+               else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000))
+                       return STV090x_RANGEOK;
+               else
+                       return STV090x_OUTOFRANGE; /* Out of Range */
+       } else {
+               if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
+                       return STV090x_RANGEOK;
+               else
+                       return STV090x_OUTOFRANGE;
+       }
+
+       return STV090x_OUTOFRANGE;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static u32 stv090x_get_tmgoffst(struct stv090x_state *state, u32 srate)
+{
+       s32 offst_tmg;
+
+       offst_tmg  = STV090x_READ_DEMOD(state, TMGREG2) << 16;
+       offst_tmg |= STV090x_READ_DEMOD(state, TMGREG1) <<  8;
+       offst_tmg |= STV090x_READ_DEMOD(state, TMGREG0);
+
+       offst_tmg = comp2(offst_tmg, 24); /* 2's complement */
+       if (!offst_tmg)
+               offst_tmg = 1;
+
+       offst_tmg  = ((s32) srate * 10) / ((s32) 0x1000000 / offst_tmg);
+       offst_tmg /= 320;
+
+       return offst_tmg;
+}
+
+static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_modcod modcod, s32 pilots)
+{
+       u8 aclc = 0x29;
+       s32 i;
+       struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low;
+
+       if (state->dev_ver == 0x20) {
+               car_loop                = stv090x_s2_crl_cut20;
+               car_loop_qpsk_low       = stv090x_s2_lowqpsk_crl_cut20;
+               car_loop_apsk_low       = stv090x_s2_apsk_crl_cut20;
+       } else {
+               /* >= Cut 3 */
+               car_loop                = stv090x_s2_crl_cut30;
+               car_loop_qpsk_low       = stv090x_s2_lowqpsk_crl_cut30;
+               car_loop_apsk_low       = stv090x_s2_apsk_crl_cut30;
+       }
+
+       if (modcod < STV090x_QPSK_12) {
+               i = 0;
+               while ((i < 3) && (modcod != car_loop_qpsk_low[i].modcod))
+                       i++;
+
+               if (i >= 3)
+                       i = 2;
+
+       } else {
+               i = 0;
+               while ((i < 14) && (modcod != car_loop[i].modcod))
+                       i++;
+
+               if (i >= 14) {
+                       i = 0;
+                       while ((i < 11) && (modcod != car_loop_apsk_low[i].modcod))
+                               i++;
+
+                       if (i >= 11)
+                               i = 10;
+               }
+       }
+
+       if (modcod <= STV090x_QPSK_25) {
+               if (pilots) {
+                       if (state->srate <= 3000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_2;
+                       else if (state->srate <= 7000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_5;
+                       else if (state->srate <= 15000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_10;
+                       else if (state->srate <= 25000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_20;
+                       else
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_30;
+               } else {
+                       if (state->srate <= 3000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_2;
+                       else if (state->srate <= 7000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_5;
+                       else if (state->srate <= 15000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_10;
+                       else if (state->srate <= 25000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_20;
+                       else
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_30;
+               }
+
+       } else if (modcod <= STV090x_8PSK_910) {
+               if (pilots) {
+                       if (state->srate <= 3000000)
+                               aclc = car_loop[i].crl_pilots_on_2;
+                       else if (state->srate <= 7000000)
+                               aclc = car_loop[i].crl_pilots_on_5;
+                       else if (state->srate <= 15000000)
+                               aclc = car_loop[i].crl_pilots_on_10;
+                       else if (state->srate <= 25000000)
+                               aclc = car_loop[i].crl_pilots_on_20;
+                       else
+                               aclc = car_loop[i].crl_pilots_on_30;
+               } else {
+                       if (state->srate <= 3000000)
+                               aclc = car_loop[i].crl_pilots_off_2;
+                       else if (state->srate <= 7000000)
+                               aclc = car_loop[i].crl_pilots_off_5;
+                       else if (state->srate <= 15000000)
+                               aclc = car_loop[i].crl_pilots_off_10;
+                       else if (state->srate <= 25000000)
+                               aclc = car_loop[i].crl_pilots_off_20;
+                       else
+                               aclc = car_loop[i].crl_pilots_off_30;
+               }
+       } else { /* 16APSK and 32APSK */
+               if (state->srate <= 3000000)
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_2;
+               else if (state->srate <= 7000000)
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_5;
+               else if (state->srate <= 15000000)
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_10;
+               else if (state->srate <= 25000000)
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_20;
+               else
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_30;
+       }
+
+       return aclc;
+}
+
+static u8 stv090x_optimize_carloop_short(struct stv090x_state *state)
+{
+       struct stv090x_short_frame_crloop *short_crl;
+       s32 index = 0;
+       u8 aclc = 0x0b;
+
+       switch (state->modulation) {
+       case STV090x_QPSK:
+       default:
+               index = 0;
+               break;
+       case STV090x_8PSK:
+               index = 1;
+               break;
+       case STV090x_16APSK:
+               index = 2;
+               break;
+       case STV090x_32APSK:
+               index = 3;
+               break;
+       }
+
+       if (state->dev_ver >= 0x30)
+               short_crl = stv090x_s2_short_crl_cut20;
+       else if (state->dev_ver >= 0x20)
+               short_crl = stv090x_s2_short_crl_cut30;
+
+       if (state->srate <= 3000000)
+               aclc = short_crl[index].crl_2;
+       else if (state->srate <= 7000000)
+               aclc = short_crl[index].crl_5;
+       else if (state->srate <= 15000000)
+               aclc = short_crl[index].crl_10;
+       else if (state->srate <= 25000000)
+               aclc = short_crl[index].crl_20;
+       else
+               aclc = short_crl[index].crl_30;
+
+       return aclc;
+}
+
+static int stv090x_optimize_track(struct stv090x_state *state)
+{
+       struct dvb_frontend *fe = &state->frontend;
+
+       enum stv090x_rolloff rolloff;
+       enum stv090x_modcod modcod;
+
+       s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0;
+       u32 reg;
+
+       srate  = stv090x_get_srate(state, state->mclk);
+       srate += stv090x_get_tmgoffst(state, srate);
+
+       switch (state->delsys) {
+       case STV090x_DVBS1:
+       case STV090x_DSS:
+               if (state->algo == STV090x_SEARCH_AUTO) {
+                       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+                       STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+                       STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+                       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                               goto err;
+               }
+               reg = STV090x_READ_DEMOD(state, DEMOD);
+               STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
+               STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x01);
+               if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+                       goto err;
+
+               if (state->dev_ver >= 0x30) {
+                       if (stv090x_get_viterbi(state) < 0)
+                               goto err;
+
+                       if (state->fec == STV090x_PR12) {
+                               if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x98) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
+                                       goto err;
+                       } else {
+                               if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x18) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
+                                       goto err;
+                       }
+               }
+
+               if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
+                       goto err;
+               break;
+
+       case STV090x_DVBS2:
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0)
+                       goto err;
+               if (state->frame_len == STV090x_LONG_FRAME) {
+                       reg = STV090x_READ_DEMOD(state, DMDMODCOD);
+                       modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
+                       pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
+                       aclc = stv090x_optimize_carloop(state, modcod, pilots);
+                       if (modcod <= STV090x_QPSK_910) {
+                               STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc);
+                       } else if (modcod <= STV090x_8PSK_910) {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
+                                       goto err;
+                       }
+                       if ((state->demod_mode == STV090x_SINGLE) && (modcod > STV090x_8PSK_910)) {
+                               if (modcod <= STV090x_16APSK_910) {
+                                       if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
+                                               goto err;
+                               } else {
+                                       if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
+                                               goto err;
+                               }
+                       }
+               } else {
+                       /*Carrier loop setting for short frame*/
+                       aclc = stv090x_optimize_carloop_short(state);
+                       if (state->modulation == STV090x_QPSK) {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc) < 0)
+                                       goto err;
+                       } else if (state->modulation == STV090x_8PSK) {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
+                                       goto err;
+                       } else if (state->modulation == STV090x_16APSK) {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
+                                       goto err;
+                       } else if (state->modulation == STV090x_32APSK)  {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
+                                       goto err;
+                       }
+               }
+
+               STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */
+               break;
+
+       case STV090x_UNKNOWN:
+       default:
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+               break;
+       }
+
+       f_1 = STV090x_READ_DEMOD(state, CFR2);
+       f_0 = STV090x_READ_DEMOD(state, CFR1);
+       reg = STV090x_READ_DEMOD(state, TMGOBS);
+       rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
+
+       if (state->algo == STV090x_BLIND_SEARCH) {
+               STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00);
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0)
+                       goto err;
+
+               if (stv090x_set_srate(state, srate) < 0)
+                       goto err;
+               blind_tune = 1;
+       }
+
+       if (state->dev_ver >= 0x20) {
+               if ((state->search_mode == STV090x_SEARCH_DVBS1)        ||
+                   (state->search_mode == STV090x_SEARCH_DSS)          ||
+                   (state->search_mode == STV090x_SEARCH_AUTO)) {
+
+                       if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x0a) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x00) < 0)
+                               goto err;
+               }
+       }
+
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+               goto err;
+
+       /* AUTO tracking MODE */
+       if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x80) < 0)
+               goto err;
+       /* AUTO tracking MODE */
+       if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0)
+               goto err;
+
+       if ((state->dev_ver >= 0x20) || (blind_tune == 1) || (state->srate < 10000000)) {
+               /* update initial carrier freq with the found freq offset */
+               if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+                       goto err;
+               state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000;
+
+               if ((state->dev_ver >= 0x20) || (blind_tune == 1)) {
+
+                       if (state->algo != STV090x_WARM_SEARCH) {
+
+                               if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                                       goto err;
+
+                               if (state->config->tuner_set_bandwidth) {
+                                       if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+                                               goto err;
+                               }
+
+                               if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                                       goto err;
+
+                       }
+               }
+               if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000))
+                       msleep(50); /* blind search: wait 50ms for SR stabilization */
+               else
+                       msleep(5);
+
+               stv090x_get_lock_tmg(state);
+
+               if (!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) {
+                       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+                               goto err;
+
+                       i = 0;
+
+                       while ((!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) && (i <= 2)) {
+
+                               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+                                       goto err;
+                               i++;
+                       }
+               }
+
+       }
+
+       if (state->dev_ver >= 0x20) {
+               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+                       goto err;
+       }
+
+       if ((state->delsys == STV090x_DVBS1) || (state->delsys == STV090x_DSS))
+               stv090x_set_vit_thtracq(state);
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_feclock(struct stv090x_state *state, s32 timeout)
+{
+       s32 timer = 0, lock = 0, stat;
+       u32 reg;
+
+       while ((timer < timeout) && (!lock)) {
+               reg = STV090x_READ_DEMOD(state, DMDSTATE);
+               stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+               switch (stat) {
+               case 0: /* searching */
+               case 1: /* first PLH detected */
+               default:
+                       lock = 0;
+                       break;
+
+               case 2: /* DVB-S2 mode */
+                       reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
+                       lock = STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD);
+                       break;
+
+               case 3: /* DVB-S1/legacy mode */
+                       reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
+                       lock = STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD);
+                       break;
+               }
+               if (!lock) {
+                       msleep(10);
+                       timer += 10;
+               }
+       }
+       return lock;
+}
+
+static int stv090x_get_lock(struct stv090x_state *state, s32 timeout_dmd, s32 timeout_fec)
+{
+       u32 reg;
+       s32 timer = 0;
+       int lock;
+
+       lock = stv090x_get_dmdlock(state, timeout_dmd);
+       if (lock)
+               lock = stv090x_get_feclock(state, timeout_fec);
+
+       if (lock) {
+               lock = 0;
+
+               while ((timer < timeout_fec) && (!lock)) {
+                       reg = STV090x_READ_DEMOD(state, TSSTATUS);
+                       lock = STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD);
+                       msleep(1);
+                       timer++;
+               }
+       }
+
+       return lock;
+}
+
+static int stv090x_set_s2rolloff(struct stv090x_state *state)
+{
+       u32 reg;
+
+       if (state->dev_ver <= 0x20) {
+               /* rolloff to auto mode if DVBS2 */
+               reg = STV090x_READ_DEMOD(state, DEMOD);
+               STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+                       goto err;
+       } else {
+               /* DVB-S2 rolloff to auto mode if DVBS2 */
+               reg = STV090x_READ_DEMOD(state, DEMOD);
+               STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+                       goto err;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+
+static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
+{
+       struct dvb_frontend *fe = &state->frontend;
+       enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
+       u32 reg;
+       s32 timeout_dmd = 500, timeout_fec = 50, agc1_power, power_iq = 0, i;
+       int lock = 0, low_sr = 0, no_signal = 0;
+
+       reg = STV090x_READ_DEMOD(state, TSCFGH);
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */
+       if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */
+               goto err;
+
+       if (state->dev_ver >= 0x20) {
+               if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) /* cut 2.0 */
+                       goto err;
+       }
+
+       stv090x_get_lock_tmg(state);
+
+       if (state->algo == STV090x_BLIND_SEARCH) {
+               state->tuner_bw = 2 * 36000000; /* wide bw for unknown srate */
+               if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) /* wider srate scan */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
+                       goto err;
+               if (stv090x_set_srate(state, 1000000) < 0) /* inital srate = 1Msps */
+                       goto err;
+       } else {
+               /* known srate */
+               if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
+                       goto err;
+
+               if (state->srate < 2000000) {
+                       /* SR < 2MSPS */
+                       if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x63) < 0)
+                               goto err;
+               } else {
+                       /* SR >= 2Msps */
+                       if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+                       goto err;
+
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0)
+                               goto err;
+                       if (state->algo == STV090x_COLD_SEARCH)
+                               state->tuner_bw = (15 * (stv090x_car_width(state->srate, state->rolloff) + 10000000)) / 10;
+                       else if (state->algo == STV090x_WARM_SEARCH)
+                               state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + 10000000;
+               }
+
+               /* if cold start or warm  (Symbolrate is known)
+                * use a Narrow symbol rate scan range
+                */
+               if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) /* narrow srate scan */
+                       goto err;
+
+               if (stv090x_set_srate(state, state->srate) < 0)
+                       goto err;
+
+               if (stv090x_set_max_srate(state, state->mclk, state->srate) < 0)
+                       goto err;
+               if (stv090x_set_min_srate(state, state->mclk, state->srate) < 0)
+                       goto err;
+
+               if (state->srate >= 10000000)
+                       low_sr = 0;
+               else
+                       low_sr = 1;
+       }
+
+       /* Setup tuner */
+       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+               goto err;
+
+       if (state->config->tuner_set_bbgain) {
+               if (state->config->tuner_set_bbgain(fe, 10) < 0) /* 10dB */
+                       goto err;
+       }
+
+       if (state->config->tuner_set_frequency) {
+               if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+                       goto err;
+       }
+
+       if (state->config->tuner_set_bandwidth) {
+               if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+                       goto err;
+       }
+
+       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+               goto err;
+
+       msleep(50);
+
+       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+               goto err;
+
+       if (state->config->tuner_get_status) {
+               if (state->config->tuner_get_status(fe, &reg) < 0)
+                       goto err;
+       }
+
+       if (reg)
+               dprintk(FE_DEBUG, 1, "Tuner phase locked");
+       else
+               dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+               goto err;
+
+       msleep(10);
+       agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1),
+                               STV090x_READ_DEMOD(state, AGCIQIN0));
+
+       if (agc1_power == 0) {
+               /* If AGC1 integrator value is 0
+                * then read POWERI, POWERQ
+                */
+               for (i = 0; i < 5; i++) {
+                       power_iq += (STV090x_READ_DEMOD(state, POWERI) +
+                                    STV090x_READ_DEMOD(state, POWERQ)) >> 1;
+               }
+               power_iq /= 5;
+       }
+
+       if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) {
+               dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq);
+               lock = 0;
+
+       } else {
+               reg = STV090x_READ_DEMOD(state, DEMOD);
+               STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion);
+
+               if (state->dev_ver <= 0x20) {
+                       /* rolloff to auto mode if DVBS2 */
+                       STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1);
+               } else {
+                       /* DVB-S2 rolloff to auto mode if DVBS2 */
+                       STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 1);
+               }
+               if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+                       goto err;
+
+               if (stv090x_delivery_search(state) < 0)
+                       goto err;
+
+               if (state->algo != STV090x_BLIND_SEARCH) {
+                       if (stv090x_start_search(state) < 0)
+                               goto err;
+               }
+       }
+
+       /* need to check for AGC1 state */
+
+
+
+       if (state->algo == STV090x_BLIND_SEARCH)
+               lock = stv090x_blind_search(state);
+
+       else if (state->algo == STV090x_COLD_SEARCH)
+               lock = stv090x_get_coldlock(state, timeout_dmd);
+
+       else if (state->algo == STV090x_WARM_SEARCH)
+               lock = stv090x_get_dmdlock(state, timeout_dmd);
+
+       if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) {
+               if (!low_sr) {
+                       if (stv090x_chk_tmg(state))
+                               lock = stv090x_sw_algo(state);
+               }
+       }
+
+       if (lock)
+               signal_state = stv090x_get_sig_params(state);
+
+       if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */
+               stv090x_optimize_track(state);
+
+               if (state->dev_ver >= 0x20) {
+                       /* >= Cut 2.0 :release TS reset after
+                        * demod lock and optimized Tracking
+                        */
+                       reg = STV090x_READ_DEMOD(state, TSCFGH);
+                       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
+                       if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+                               goto err;
+
+                       msleep(3);
+
+                       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* merger reset */
+                       if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+                               goto err;
+
+                       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
+                       if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+                               goto err;
+               }
+
+               if (stv090x_get_lock(state, timeout_fec, timeout_fec)) {
+                       lock = 1;
+                       if (state->delsys == STV090x_DVBS2) {
+                               stv090x_set_s2rolloff(state);
+
+                               reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+                               STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 1);
+                               if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+                                       goto err;
+                               /* Reset DVBS2 packet delinator error counter */
+                               reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+                               STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 0);
+                               if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+                                       goto err;
+
+                               if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */
+                                       goto err;
+                       } else {
+                               if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
+                                       goto err;
+                       }
+                       /* Reset the Total packet counter */
+                       if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0x00) < 0)
+                               goto err;
+                       /* Reset the packet Error counter2 */
+                       if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
+                               goto err;
+               } else {
+                       lock = 0;
+                       signal_state = STV090x_NODATA;
+                       no_signal = stv090x_chk_signal(state);
+               }
+       }
+       return signal_state;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *props = &fe->dtv_property_cache;
+
+       state->delsys = props->delivery_system;
+       state->frequency = p->frequency;
+       state->srate = p->u.qpsk.symbol_rate;
+       state->search_mode = STV090x_SEARCH_AUTO;
+       state->algo = STV090x_COLD_SEARCH;
+       state->fec = STV090x_PRERR;
+       state->search_range = 2000000;
+
+       if (stv090x_algo(state) == STV090x_RANGEOK) {
+               dprintk(FE_DEBUG, 1, "Search success!");
+               return DVBFE_ALGO_SEARCH_SUCCESS;
+       } else {
+               dprintk(FE_DEBUG, 1, "Search failed!");
+               return DVBFE_ALGO_SEARCH_FAILED;
+       }
+
+       return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+/* FIXME! */
+static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+       u8 search_state;
+
+       reg = STV090x_READ_DEMOD(state, DMDSTATE);
+       search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+       switch (search_state) {
+       case 0: /* searching */
+       case 1: /* first PLH detected */
+       default:
+               dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)");
+               *status = 0;
+               break;
+
+       case 2: /* DVB-S2 mode */
+               dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2");
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
+                       reg = STV090x_READ_DEMOD(state, TSSTATUS);
+                       if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
+                               *status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+                       }
+               }
+               break;
+
+       case 3: /* DVB-S1/legacy mode */
+               dprintk(FE_DEBUG, 1, "Delivery system: DVB-S");
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
+                       reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
+                       if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) {
+                               reg = STV090x_READ_DEMOD(state, TSSTATUS);
+                               if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
+                                       *status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+                               }
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int stv090x_read_per(struct dvb_frontend *fe, u32 *per)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+
+       s32 count_4, count_3, count_2, count_1, count_0, count;
+       u32 reg, h, m, l;
+       enum fe_status status;
+
+       stv090x_read_status(fe, &status);
+       if (!(status & FE_HAS_LOCK)) {
+               *per = 1 << 23; /* Max PER */
+       } else {
+               /* Counter 2 */
+               reg = STV090x_READ_DEMOD(state, ERRCNT22);
+               h = STV090x_GETFIELD_Px(reg, ERR_CNT2_FIELD);
+
+               reg = STV090x_READ_DEMOD(state, ERRCNT21);
+               m = STV090x_GETFIELD_Px(reg, ERR_CNT21_FIELD);
+
+               reg = STV090x_READ_DEMOD(state, ERRCNT20);
+               l = STV090x_GETFIELD_Px(reg, ERR_CNT20_FIELD);
+
+               *per = ((h << 16) | (m << 8) | l);
+
+               count_4 = STV090x_READ_DEMOD(state, FBERCPT4);
+               count_3 = STV090x_READ_DEMOD(state, FBERCPT3);
+               count_2 = STV090x_READ_DEMOD(state, FBERCPT2);
+               count_1 = STV090x_READ_DEMOD(state, FBERCPT1);
+               count_0 = STV090x_READ_DEMOD(state, FBERCPT0);
+
+               if ((!count_4) && (!count_3)) {
+                       count  = (count_2 & 0xff) << 16;
+                       count |= (count_1 & 0xff) <<  8;
+                       count |=  count_0 & 0xff;
+               } else {
+                       count = 1 << 24;
+               }
+               if (count == 0)
+                       *per = 1;
+       }
+       if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val)
+{
+       int res = 0;
+       int min = 0, med;
+
+       if (val < tab[min].read)
+               res = tab[min].real;
+       else if (val >= tab[max].read)
+               res = tab[max].real;
+       else {
+               while ((max - min) > 1) {
+                       med = (max + min) / 2;
+                       if (val >= tab[min].read && val < tab[med].read)
+                               max = med;
+                       else
+                               min = med;
+               }
+               res = ((val - tab[min].read) *
+                      (tab[max].real - tab[min].real) /
+                      (tab[max].read - tab[min].read)) +
+                       tab[min].real;
+       }
+
+       return res;
+}
+
+static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+       s32 agc;
+
+       reg = STV090x_READ_DEMOD(state, AGCIQIN1);
+       agc = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
+
+       *strength = stv090x_table_lookup(stv090x_rf_tab, ARRAY_SIZE(stv090x_rf_tab) - 1, agc);
+       if (agc > stv090x_rf_tab[0].read)
+               *strength = 5;
+       else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read)
+               *strength = -100;
+
+       return 0;
+}
+
+static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg_0, reg_1, reg, i;
+       s32 val_0, val_1, val = 0;
+       u8 lock_f;
+
+       switch (state->delsys) {
+       case STV090x_DVBS2:
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+               if (lock_f) {
+                       msleep(5);
+                       for (i = 0; i < 16; i++) {
+                               reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1);
+                               val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
+                               reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0);
+                               val_0 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
+                               val  += MAKEWORD16(val_1, val_0);
+                               msleep(1);
+                       }
+                       val /= 16;
+                       *cnr = stv090x_table_lookup(stv090x_s2cn_tab, ARRAY_SIZE(stv090x_s2cn_tab) - 1, val);
+                       if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s2cn_tab) - 1].read)
+                               *cnr = 1000;
+               }
+               break;
+
+       case STV090x_DVBS1:
+       case STV090x_DSS:
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+               if (lock_f) {
+                       msleep(5);
+                       for (i = 0; i < 16; i++) {
+                               reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1);
+                               val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
+                               reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0);
+                               val_0 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
+                               val  += MAKEWORD16(val_1, val_0);
+                               msleep(1);
+                       }
+                       val /= 16;
+                       *cnr = stv090x_table_lookup(stv090x_s1cn_tab, ARRAY_SIZE(stv090x_s1cn_tab) - 1, val);
+                       if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s1cn_tab) - 1].read)
+                               *cnr = 1000;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int stv090x_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+       switch (tone) {
+       case SEC_TONE_ON:
+               STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
+               STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+                       goto err;
+               STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+               if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+                       goto err;
+               break;
+
+       case SEC_TONE_OFF:
+               STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
+               STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+                       goto err;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+
+static enum dvbfe_algo stv090x_frontend_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_CUSTOM;
+}
+
+static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg, idle = 0, fifo_full = 1;
+       int i;
+
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+
+       STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 2);
+       STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+       STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       for (i = 0; i < cmd->msg_len; i++) {
+
+               while (fifo_full) {
+                       reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+                       fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
+               }
+
+               if (STV090x_WRITE_DEMOD(state, DISTXDATA, cmd->msg[i]) < 0)
+                       goto err;
+       }
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+       STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       i = 0;
+
+       while ((!idle) && (i < 10)) {
+               reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+               idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
+               msleep(10);
+               i++;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg, idle = 0, fifo_full = 1;
+       u8 mode, value;
+       int i;
+
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+
+       if (burst == SEC_MINI_A) {
+               mode = 3;
+               value = 0x00;
+       } else {
+               mode = 2;
+               value = 0xFF;
+       }
+
+       STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, mode);
+       STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+       STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       while (fifo_full) {
+               reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+               fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
+       }
+
+       if (STV090x_WRITE_DEMOD(state, DISTXDATA, value) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+       STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       i = 0;
+
+       while ((!idle) && (i < 10)) {
+               reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+               idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
+               msleep(10);
+               i++;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg = 0, i = 0, rx_end = 0;
+
+       while ((rx_end != 1) && (i < 10)) {
+               msleep(10);
+               i++;
+               reg = STV090x_READ_DEMOD(state, DISRX_ST0);
+               rx_end = STV090x_GETFIELD_Px(reg, RX_END_FIELD);
+       }
+
+       if (rx_end) {
+               reply->msg_len = STV090x_GETFIELD_Px(reg, FIFO_BYTENBR_FIELD);
+               for (i = 0; i < reply->msg_len; i++)
+                       reply->msg[i] = STV090x_READ_DEMOD(state, DISRXDATA);
+       }
+
+       return 0;
+}
+
+static int stv090x_sleep(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+
+       dprintk(FE_DEBUG, 1, "Set %s to sleep",
+               state->device == STV0900 ? "STV0900" : "STV0903");
+
+       reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+       STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
+       if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+               goto err;
+
+       reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+       STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
+       if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_wakeup(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+
+       dprintk(FE_DEBUG, 1, "Wake %s from standby",
+               state->device == STV0900 ? "STV0900" : "STV0903");
+
+       reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+       STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00);
+       if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+               goto err;
+
+       reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+       STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1);
+       if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static void stv090x_release(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+
+       kfree(state);
+}
+
+static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc_mode)
+{
+       u32 reg = 0;
+
+       switch (ldpc_mode) {
+       case STV090x_DUAL:
+       default:
+               if ((state->demod_mode != STV090x_DUAL) || (STV090x_GETFIELD(reg, DDEMOD_FIELD) != 1)) {
+                       /* set LDPC to dual mode */
+                       if (stv090x_write_reg(state, STV090x_GENCFG, 0x1d) < 0)
+                               goto err;
+
+                       state->demod_mode = STV090x_DUAL;
+
+                       reg = stv090x_read_reg(state, STV090x_TSTRES0);
+                       STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
+                       if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+                               goto err;
+                       STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
+                       if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+                               goto err;
+
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
+                               goto err;
+
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
+                               goto err;
+
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
+                               goto err;
+               }
+               break;
+
+       case STV090x_SINGLE:
+               if (stv090x_stop_modcod(state) < 0)
+                       goto err;
+               if (stv090x_activate_modcod_single(state) < 0)
+                       goto err;
+
+               if (state->demod == STV090x_DEMODULATOR_1) {
+                       if (stv090x_write_reg(state, STV090x_GENCFG, 0x06) < 0) /* path 2 */
+                               goto err;
+               } else {
+                       if (stv090x_write_reg(state, STV090x_GENCFG, 0x04) < 0) /* path 1 */
+                               goto err;
+               }
+
+               reg = stv090x_read_reg(state, STV090x_TSTRES0);
+               STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
+               if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+                       goto err;
+               STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
+               if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+                       goto err;
+
+               reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+               STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x01);
+               if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+                       goto err;
+               STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+                       goto err;
+               break;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+/* return (Hz), clk in Hz*/
+static u32 stv090x_get_mclk(struct stv090x_state *state)
+{
+       const struct stv090x_config *config = state->config;
+       u32 div, reg;
+       u8 ratio;
+
+       div = stv090x_read_reg(state, STV090x_NCOARSE);
+       reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+       ratio = STV090x_GETFIELD(reg, SELX1RATIO_FIELD) ? 4 : 6;
+
+       return (div + 1) * config->xtal / ratio; /* kHz */
+}
+
+static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk)
+{
+       const struct stv090x_config *config = state->config;
+       u32 reg, div, clk_sel;
+
+       reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+       clk_sel = ((STV090x_GETFIELD(reg, SELX1RATIO_FIELD) == 1) ? 4 : 6);
+
+       div = ((clk_sel * mclk) / config->xtal) - 1;
+
+       reg = stv090x_read_reg(state, STV090x_NCOARSE);
+       STV090x_SETFIELD(reg, M_DIV_FIELD, div);
+       if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0)
+               goto err;
+
+       state->mclk = stv090x_get_mclk(state);
+
+       /*Set the DiseqC frequency to 22KHz */
+       div = state->mclk / 704000;
+       if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_tspath(struct stv090x_state *state)
+{
+       u32 reg;
+
+       if (state->dev_ver >= 0x20) {
+               switch (state->config->ts1_mode) {
+               case STV090x_TSMODE_PARALLEL_PUNCTURED:
+               case STV090x_TSMODE_DVBCI:
+                       switch (state->config->ts2_mode) {
+                       case STV090x_TSMODE_SERIAL_PUNCTURED:
+                       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+                       default:
+                               stv090x_write_reg(state, STV090x_TSGENERAL, 0x00);
+                               break;
+
+                       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+                       case STV090x_TSMODE_DVBCI:
+                               if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x06) < 0) /* Mux'd stream mode */
+                                       goto err;
+                               reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+                               STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+                               if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+                                       goto err;
+                               reg = stv090x_read_reg(state, STV090x_P2_TSCFGM);
+                               STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+                               if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0)
+                                       goto err;
+                               if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
+                                       goto err;
+                               if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
+                                       goto err;
+                               break;
+                       }
+                       break;
+
+               case STV090x_TSMODE_SERIAL_PUNCTURED:
+               case STV090x_TSMODE_SERIAL_CONTINUOUS:
+               default:
+                       switch (state->config->ts2_mode) {
+                       case STV090x_TSMODE_SERIAL_PUNCTURED:
+                       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+                       default:
+                               if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
+                                       goto err;
+                               break;
+
+                       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+                       case STV090x_TSMODE_DVBCI:
+                               if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0a) < 0)
+                                       goto err;
+                               break;
+                       }
+                       break;
+               }
+       } else {
+               switch (state->config->ts1_mode) {
+               case STV090x_TSMODE_PARALLEL_PUNCTURED:
+               case STV090x_TSMODE_DVBCI:
+                       switch (state->config->ts2_mode) {
+                       case STV090x_TSMODE_SERIAL_PUNCTURED:
+                       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+                       default:
+                               stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10);
+                               break;
+
+                       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+                       case STV090x_TSMODE_DVBCI:
+                               stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x16);
+                               reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+                               STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+                               if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+                                       goto err;
+                               reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+                               STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 0);
+                               if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+                                       goto err;
+                               if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
+                                       goto err;
+                               if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
+                                       goto err;
+                               break;
+                       }
+                       break;
+
+               case STV090x_TSMODE_SERIAL_PUNCTURED:
+               case STV090x_TSMODE_SERIAL_CONTINUOUS:
+               default:
+                       switch (state->config->ts2_mode) {
+                       case STV090x_TSMODE_SERIAL_PUNCTURED:
+                       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+                       default:
+                               stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14);
+                               break;
+
+                       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+                       case STV090x_TSMODE_DVBCI:
+                               stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x12);
+                               break;
+                       }
+                       break;
+               }
+       }
+
+       switch (state->config->ts1_mode) {
+       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+               reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+               if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_DVBCI:
+               reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+               if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_SERIAL_PUNCTURED:
+               reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+               if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+               reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+               if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       default:
+               break;
+       }
+
+       switch (state->config->ts2_mode) {
+       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+               reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+               if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_DVBCI:
+               reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+               if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_SERIAL_PUNCTURED:
+               reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+               if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+               reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+               if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       default:
+               break;
+       }
+       reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+       if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+               goto err;
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+       if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+               goto err;
+
+       reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+       if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+               goto err;
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+       if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_init(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       const struct stv090x_config *config = state->config;
+       u32 reg;
+
+       if (stv090x_wakeup(fe) < 0) {
+               dprintk(FE_ERROR, 1, "Error waking device");
+               goto err;
+       }
+
+       if (stv090x_ldpc_mode(state, state->demod_mode) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, TNRCFG2);
+       STV090x_SETFIELD_Px(reg, TUN_IQSWAP_FIELD, state->inversion);
+       if (STV090x_WRITE_DEMOD(state, TNRCFG2, reg) < 0)
+               goto err;
+       reg = STV090x_READ_DEMOD(state, DEMOD);
+       STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
+       if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+               goto err;
+
+       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+               goto err;
+
+       if (config->tuner_set_mode) {
+               if (config->tuner_set_mode(fe, TUNER_WAKE) < 0)
+                       goto err;
+       }
+
+       if (config->tuner_init) {
+               if (config->tuner_init(fe) < 0)
+                       goto err;
+       }
+
+       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+               goto err;
+
+       if (stv090x_set_tspath(state) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_setup(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       const struct stv090x_config *config = state->config;
+       const struct stv090x_reg *stv090x_initval = NULL;
+       const struct stv090x_reg *stv090x_cut20_val = NULL;
+       unsigned long t1_size = 0, t2_size = 0;
+       u32 reg = 0;
+
+       int i;
+
+       if (state->device == STV0900) {
+               dprintk(FE_DEBUG, 1, "Initializing STV0900");
+               stv090x_initval = stv0900_initval;
+               t1_size = ARRAY_SIZE(stv0900_initval);
+               stv090x_cut20_val = stv0900_cut20_val;
+               t2_size = ARRAY_SIZE(stv0900_cut20_val);
+       } else if (state->device == STV0903) {
+               dprintk(FE_DEBUG, 1, "Initializing STV0903");
+               stv090x_initval = stv0903_initval;
+               t1_size = ARRAY_SIZE(stv0903_initval);
+               stv090x_cut20_val = stv0903_cut20_val;
+               t2_size = ARRAY_SIZE(stv0903_cut20_val);
+       }
+
+       /* STV090x init */
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Stop Demod */
+               goto err;
+
+       msleep(5);
+
+       if (STV090x_WRITE_DEMOD(state, TNRCFG, 0x6c) < 0) /* check register ! (No Tuner Mode) */
+               goto err;
+
+       STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level);
+       if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0) /* repeater OFF */
+               goto err;
+
+       if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */
+               goto err;
+       msleep(5);
+       if (stv090x_write_reg(state, STV090x_I2CCFG, 0x08) < 0) /* 1/41 oversampling */
+               goto err;
+       if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0) /* enable PLL */
+               goto err;
+       msleep(5);
+
+       /* write initval */
+       dprintk(FE_DEBUG, 1, "Setting up initial values");
+       for (i = 0; i < t1_size; i++) {
+               if (stv090x_write_reg(state, stv090x_initval[i].addr, stv090x_initval[i].data) < 0)
+                       goto err;
+       }
+
+       state->dev_ver = stv090x_read_reg(state, STV090x_MID);
+       if (state->dev_ver >= 0x20) {
+               if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
+                       goto err;
+
+               /* write cut20_val*/
+               dprintk(FE_DEBUG, 1, "Setting up Cut 2.0 initial values");
+               for (i = 0; i < t2_size; i++) {
+                       if (stv090x_write_reg(state, stv090x_cut20_val[i].addr, stv090x_cut20_val[i].data) < 0)
+                               goto err;
+               }
+
+       } else if (state->dev_ver < 0x20) {
+               dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!",
+                       state->dev_ver);
+
+               goto err;
+       } else if (state->dev_ver > 0x30) {
+               /* we shouldn't bail out from here */
+               dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!",
+                       state->dev_ver);
+       }
+
+       if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0)
+               goto err;
+       if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
+               goto err;
+
+       stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
+       msleep(5);
+       if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0)
+               goto err;
+       stv090x_get_mclk(state);
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static struct dvb_frontend_ops stv090x_ops = {
+
+       .info = {
+               .name                   = "STV090x Multistandard",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 0,
+               .frequency_tolerance    = 0,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+               .caps                   = FE_CAN_INVERSION_AUTO |
+                                         FE_CAN_FEC_AUTO       |
+                                         FE_CAN_QPSK           |
+                                         FE_CAN_2G_MODULATION
+       },
+
+       .release                        = stv090x_release,
+       .init                           = stv090x_init,
+
+       .sleep                          = stv090x_sleep,
+       .get_frontend_algo              = stv090x_frontend_algo,
+
+       .i2c_gate_ctrl                  = stv090x_i2c_gate_ctrl,
+
+       .diseqc_send_master_cmd         = stv090x_send_diseqc_msg,
+       .diseqc_send_burst              = stv090x_send_diseqc_burst,
+       .diseqc_recv_slave_reply        = stv090x_recv_slave_reply,
+       .set_tone                       = stv090x_set_tone,
+
+       .search                         = stv090x_search,
+       .read_status                    = stv090x_read_status,
+       .read_ber                       = stv090x_read_per,
+       .read_signal_strength           = stv090x_read_signal_strength,
+       .read_snr                       = stv090x_read_cnr
+};
+
+
+struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+                                   struct i2c_adapter *i2c,
+                                   enum stv090x_demodulator demod)
+{
+       struct stv090x_state *state = NULL;
+
+       state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       state->verbose                          = &verbose;
+       state->config                           = config;
+       state->i2c                              = i2c;
+       state->frontend.ops                     = stv090x_ops;
+       state->frontend.demodulator_priv        = state;
+       state->demod                            = demod;
+       state->demod_mode                       = config->demod_mode; /* Single or Dual mode */
+       state->device                           = config->device;
+       state->rolloff                          = STV090x_RO_35; /* default */
+
+       if (state->demod == STV090x_DEMODULATOR_0)
+               mutex_init(&demod_lock);
+
+       if (stv090x_sleep(&state->frontend) < 0) {
+               dprintk(FE_ERROR, 1, "Error putting device to sleep");
+               goto error;
+       }
+
+       if (stv090x_setup(&state->frontend) < 0) {
+               dprintk(FE_ERROR, 1, "Error setting up device");
+               goto error;
+       }
+       if (stv090x_wakeup(&state->frontend) < 0) {
+               dprintk(FE_ERROR, 1, "Error waking device");
+               goto error;
+       }
+
+       dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x\n",
+              state->device == STV0900 ? "STV0900" : "STV0903",
+              demod,
+              state->dev_ver);
+
+       return &state->frontend;
+
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(stv090x_attach);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h
new file mode 100644 (file)
index 0000000..e968c98
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+       STV0900/0903 Multistandard Broadcast Frontend driver
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV090x_H
+#define __STV090x_H
+
+enum stv090x_demodulator {
+       STV090x_DEMODULATOR_0 = 1,
+       STV090x_DEMODULATOR_1
+};
+
+enum stv090x_device {
+       STV0903 =  0,
+       STV0900,
+};
+
+enum stv090x_mode {
+       STV090x_DUAL = 0,
+       STV090x_SINGLE
+};
+
+enum stv090x_tsmode {
+       STV090x_TSMODE_SERIAL_PUNCTURED = 1,
+       STV090x_TSMODE_SERIAL_CONTINUOUS,
+       STV090x_TSMODE_PARALLEL_PUNCTURED,
+       STV090x_TSMODE_DVBCI
+};
+
+enum stv090x_clkmode {
+       STV090x_CLK_INT = 0, /* Clk i/p = CLKI */
+       STV090x_CLK_EXT = 2 /* Clk i/p = XTALI */
+};
+
+enum stv090x_i2crpt {
+       STV090x_RPTLEVEL_256    = 0,
+       STV090x_RPTLEVEL_128    = 1,
+       STV090x_RPTLEVEL_64     = 2,
+       STV090x_RPTLEVEL_32     = 3,
+       STV090x_RPTLEVEL_16     = 4,
+       STV090x_RPTLEVEL_8      = 5,
+       STV090x_RPTLEVEL_4      = 6,
+       STV090x_RPTLEVEL_2      = 7,
+};
+
+struct stv090x_config {
+       enum stv090x_device     device;
+       enum stv090x_mode       demod_mode;
+       enum stv090x_clkmode    clk_mode;
+
+       u32 xtal; /* default: 8000000 */
+       u8 address; /* default: 0x68 */
+
+       u32 ref_clk; /* default: 16000000 FIXME to tuner config */
+
+       u8 ts1_mode;
+       u8 ts2_mode;
+
+       enum stv090x_i2crpt     repeater_level;
+
+       int (*tuner_init) (struct dvb_frontend *fe);
+       int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
+       int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
+       int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
+       int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
+       int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
+       int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
+       int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
+       int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
+       int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
+};
+
+#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+                                          struct i2c_adapter *i2c,
+                                          enum stv090x_demodulator demod);
+#else
+
+static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+                                                 struct i2c_adapter *i2c,
+                                                 enum stv090x_demodulator demod)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_STV090x */
+
+#endif /* __STV090x_H */
diff --git a/drivers/media/dvb/frontends/stv090x_priv.h b/drivers/media/dvb/frontends/stv090x_priv.h
new file mode 100644 (file)
index 0000000..5a4a017
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+       STV0900/0903 Multistandard Broadcast Frontend driver
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV090x_PRIV_H
+#define __STV090x_PRIV_H
+
+#include "dvb_frontend.h"
+
+#define FE_ERROR                               0
+#define FE_NOTICE                              1
+#define FE_INFO                                        2
+#define FE_DEBUG                               3
+#define FE_DEBUGREG                            4
+
+#define dprintk(__y, __z, format, arg...) do {                                         \
+       if (__z) {                                                                      \
+               if      ((verbose > FE_ERROR) && (verbose > __y))                       \
+                       printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);          \
+               else if ((verbose > FE_NOTICE) && (verbose > __y))                      \
+                       printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);       \
+               else if ((verbose > FE_INFO) && (verbose > __y))                        \
+                       printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);         \
+               else if ((verbose > FE_DEBUG) && (verbose > __y))                       \
+                       printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);        \
+       } else {                                                                        \
+               if (verbose > __y)                                                      \
+                       printk(format, ##arg);                                          \
+       }                                                                               \
+} while (0)
+
+#define STV090x_READ_DEMOD(__state, __reg) ((                  \
+       (__state)->demod == STV090x_DEMODULATOR_1)      ?       \
+       stv090x_read_reg(__state, STV090x_P2_##__reg) :         \
+       stv090x_read_reg(__state, STV090x_P1_##__reg))
+
+#define STV090x_WRITE_DEMOD(__state, __reg, __data) ((         \
+       (__state)->demod == STV090x_DEMODULATOR_1)      ?       \
+       stv090x_write_reg(__state, STV090x_P2_##__reg, __data) :\
+       stv090x_write_reg(__state, STV090x_P1_##__reg, __data))
+
+#define STV090x_ADDR_OFFST(__state, __x) ((                    \
+       (__state->demod) == STV090x_DEMODULATOR_1)      ?       \
+               STV090x_P1_##__x :                              \
+               STV090x_P2_##__x)
+
+
+#define STV090x_SETFIELD(mask, bitf, val)      (mask = (mask & (~(((1 << STV090x_WIDTH_##bitf) - 1) <<\
+                                                        STV090x_OFFST_##bitf))) | \
+                                                        (val << STV090x_OFFST_##bitf))
+
+#define STV090x_GETFIELD(val, bitf)            ((val >> STV090x_OFFST_##bitf) & ((1 << STV090x_WIDTH_##bitf) - 1))
+
+
+#define STV090x_SETFIELD_Px(mask, bitf, val)   (mask = (mask & (~(((1 << STV090x_WIDTH_Px_##bitf) - 1) <<\
+                                                        STV090x_OFFST_Px_##bitf))) | \
+                                                        (val << STV090x_OFFST_Px_##bitf))
+
+#define STV090x_GETFIELD_Px(val, bitf)         ((val >> STV090x_OFFST_Px_##bitf) & ((1 << STV090x_WIDTH_Px_##bitf) - 1))
+
+#define MAKEWORD16(__a, __b)                   (((__a) << 8) | (__b))
+
+#define MSB(__x)                               ((__x >> 8) & 0xff)
+#define LSB(__x)                               (__x & 0xff)
+
+
+#define STV090x_IQPOWER_THRESHOLD        30
+#define STV090x_SEARCH_AGC2_TH_CUT20    700
+#define STV090x_SEARCH_AGC2_TH_CUT30   1200
+
+#define STV090x_SEARCH_AGC2_TH(__ver)  \
+       ((__ver <= 0x20) ?              \
+       STV090x_SEARCH_AGC2_TH_CUT20 :  \
+       STV090x_SEARCH_AGC2_TH_CUT30)
+
+enum stv090x_signal_state {
+       STV090x_NOCARRIER,
+       STV090x_NODATA,
+       STV090x_DATAOK,
+       STV090x_RANGEOK,
+       STV090x_OUTOFRANGE
+};
+
+enum stv090x_fec {
+       STV090x_PR12 = 0,
+       STV090x_PR23,
+       STV090x_PR34,
+       STV090x_PR45,
+       STV090x_PR56,
+       STV090x_PR67,
+       STV090x_PR78,
+       STV090x_PR89,
+       STV090x_PR910,
+       STV090x_PRERR
+};
+
+enum stv090x_modulation {
+       STV090x_QPSK,
+       STV090x_8PSK,
+       STV090x_16APSK,
+       STV090x_32APSK,
+       STV090x_UNKNOWN
+};
+
+enum stv090x_frame {
+       STV090x_LONG_FRAME,
+       STV090x_SHORT_FRAME
+};
+
+enum stv090x_pilot {
+       STV090x_PILOTS_OFF,
+       STV090x_PILOTS_ON
+};
+
+enum stv090x_rolloff {
+       STV090x_RO_35,
+       STV090x_RO_25,
+       STV090x_RO_20
+};
+
+enum stv090x_inversion {
+       STV090x_IQ_AUTO,
+       STV090x_IQ_NORMAL,
+       STV090x_IQ_SWAP
+};
+
+enum stv090x_modcod {
+       STV090x_DUMMY_PLF = 0,
+       STV090x_QPSK_14,
+       STV090x_QPSK_13,
+       STV090x_QPSK_25,
+       STV090x_QPSK_12,
+       STV090x_QPSK_35,
+       STV090x_QPSK_23,
+       STV090x_QPSK_34,
+       STV090x_QPSK_45,
+       STV090x_QPSK_56,
+       STV090x_QPSK_89,
+       STV090x_QPSK_910,
+       STV090x_8PSK_35,
+       STV090x_8PSK_23,
+       STV090x_8PSK_34,
+       STV090x_8PSK_56,
+       STV090x_8PSK_89,
+       STV090x_8PSK_910,
+       STV090x_16APSK_23,
+       STV090x_16APSK_34,
+       STV090x_16APSK_45,
+       STV090x_16APSK_56,
+       STV090x_16APSK_89,
+       STV090x_16APSK_910,
+       STV090x_32APSK_34,
+       STV090x_32APSK_45,
+       STV090x_32APSK_56,
+       STV090x_32APSK_89,
+       STV090x_32APSK_910,
+       STV090x_MODCODE_UNKNOWN
+};
+
+enum stv090x_search {
+       STV090x_SEARCH_DSS = 0,
+       STV090x_SEARCH_DVBS1,
+       STV090x_SEARCH_DVBS2,
+       STV090x_SEARCH_AUTO
+};
+
+enum stv090x_algo {
+       STV090x_BLIND_SEARCH,
+       STV090x_COLD_SEARCH,
+       STV090x_WARM_SEARCH
+};
+
+enum stv090x_delsys {
+       STV090x_ERROR = 0,
+       STV090x_DVBS1 = 1,
+       STV090x_DVBS2,
+       STV090x_DSS
+};
+
+struct stv090x_long_frame_crloop {
+       enum stv090x_modcod     modcod;
+
+       u8 crl_pilots_on_2;
+       u8 crl_pilots_off_2;
+       u8 crl_pilots_on_5;
+       u8 crl_pilots_off_5;
+       u8 crl_pilots_on_10;
+       u8 crl_pilots_off_10;
+       u8 crl_pilots_on_20;
+       u8 crl_pilots_off_20;
+       u8 crl_pilots_on_30;
+       u8 crl_pilots_off_30;
+};
+
+struct stv090x_short_frame_crloop {
+       enum stv090x_modulation modulation;
+
+       u8 crl_2;  /*      SR <   3M */
+       u8 crl_5;  /*  3 < SR <=  7M */
+       u8 crl_10; /*  7 < SR <= 15M */
+       u8 crl_20; /* 10 < SR <= 25M */
+       u8 crl_30; /* 10 < SR <= 45M */
+};
+
+struct stv090x_reg {
+       u16 addr;
+       u8  data;
+};
+
+struct stv090x_tab {
+       s32 real;
+       s32 read;
+};
+
+struct stv090x_state {
+       enum stv090x_device             device;
+       enum stv090x_demodulator        demod;
+       enum stv090x_mode               demod_mode;
+       u32                             dev_ver;
+
+       struct i2c_adapter              *i2c;
+       const struct stv090x_config     *config;
+       struct dvb_frontend             frontend;
+
+       u32                             *verbose; /* Cached module verbosity */
+
+       enum stv090x_delsys             delsys;
+       enum stv090x_fec                fec;
+       enum stv090x_modulation         modulation;
+       enum stv090x_modcod             modcod;
+       enum stv090x_search             search_mode;
+       enum stv090x_frame              frame_len;
+       enum stv090x_pilot              pilots;
+       enum stv090x_rolloff            rolloff;
+       enum stv090x_inversion          inversion;
+       enum stv090x_algo               algo;
+
+       u32                             frequency;
+       u32                             srate;
+
+       s32                             mclk; /* Masterclock Divider factor */
+       s32                             tuner_bw;
+
+       u32                             tuner_refclk;
+
+       s32                             search_range;
+
+       s32                             DemodTimeout;
+       s32                             FecTimeout;
+};
+
+#endif /* __STV090x_PRIV_H */
diff --git a/drivers/media/dvb/frontends/stv090x_reg.h b/drivers/media/dvb/frontends/stv090x_reg.h
new file mode 100644 (file)
index 0000000..57b6abb
--- /dev/null
@@ -0,0 +1,2373 @@
+/*
+       STV0900/0903 Multistandard Broadcast Frontend driver
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV090x_REG_H
+#define __STV090x_REG_H
+
+#define STV090x_MID                            0xf100
+#define STV090x_OFFST_MCHIP_IDENT_FIELD                4
+#define STV090x_WIDTH_MCHIP_IDENT_FIELD                4
+#define STV090x_OFFST_MRELEASE_FIELD           0
+#define STV090x_WIDTH_MRELEASE_FIELD           4
+
+#define STV090x_DACR1                          0xf113
+#define STV090x_OFFST_DACR1_MODE_FIELD         5
+#define STV090x_WIDTH_DACR1_MODE_FIELD         3
+#define STV090x_OFFST_DACR1_VALUE_FIELD                0
+#define STV090x_WIDTH_DACR1_VALUE_FIELD                4
+
+#define STV090x_DACR2                          0xf114
+#define STV090x_OFFST_DACR2_VALUE_FIELD                0
+#define STV090x_WIDTH_DACR2_VALUE_FIELD                8
+
+#define STV090x_OUTCFG                         0xf11c
+#define STV090x_OFFST_OUTSERRS1_HZ_FIELD       6
+#define STV090x_WIDTH_OUTSERRS1_HZ_FIELD       1
+#define STV090x_OFFST_OUTSERRS2_HZ_FIELD       5
+#define STV090x_WIDTH_OUTSERRS2_HZ_FIELD       1
+#define STV090x_OFFST_OUTSERRS3_HZ_FIELD       4
+#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD       1
+#define STV090x_OFFST_OUTPARRS3_HZ_FIELD       3
+#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD       1
+
+#define STV090x_MODECFG                                0xf11d
+
+#define STV090x_IRQSTATUS3                     0xf120
+#define STV090x_OFFST_SPLL_LOCK_FIELD          5
+#define STV090x_WIDTH_SPLL_LOCK_FIELD          1
+#define STV090x_OFFST_SSTREAM_LCK_3_FIELD      4
+#define STV090x_WIDTH_SSTREAM_LCK_3_FIELD      1
+#define STV090x_OFFST_SSTREAM_LCK_2_FIELD      3
+#define STV090x_WIDTH_SSTREAM_LCK_2_FIELD      1
+#define STV090x_OFFST_SSTREAM_LCK_1_FIELD      2
+#define STV090x_WIDTH_SSTREAM_LCK_1_FIELD      1
+#define STV090x_OFFST_SDVBS1_PRF_2_FIELD       1
+#define STV090x_WIDTH_SDVBS1_PRF_2_FIELD       1
+#define STV090x_OFFST_SDVBS1_PRF_1_FIELD       0
+#define STV090x_WIDTH_SDVBS1_PRF_1_FIELD       1
+
+#define STV090x_IRQSTATUS2                     0xf121
+#define STV090x_OFFST_SSPY_ENDSIM_3_FIELD      7
+#define STV090x_WIDTH_SSPY_ENDSIM_3_FIELD      1
+#define STV090x_OFFST_SSPY_ENDSIM_2_FIELD      6
+#define STV090x_WIDTH_SSPY_ENDSIM_2_FIELD      1
+#define STV090x_OFFST_SSPY_ENDSIM_1_FIELD      5
+#define STV090x_WIDTH_SSPY_ENDSIM_1_FIELD      1
+#define STV090x_OFFST_SPKTDEL_ERROR_2_FIELD    4
+#define STV090x_WIDTH_SPKTDEL_ERROR_2_FIELD    1
+#define STV090x_OFFST_SPKTDEL_LOCKB_2_FIELD    3
+#define STV090x_WIDTH_SPKTDEL_LOCKB_2_FIELD    1
+#define STV090x_OFFST_SPKTDEL_LOCK_2_FIELD     2
+#define STV090x_WIDTH_SPKTDEL_LOCK_2_FIELD     1
+#define STV090x_OFFST_SPKTDEL_ERROR_1_FIELD    1
+#define STV090x_WIDTH_SPKTDEL_ERROR_1_FIELD    1
+#define STV090x_OFFST_SPKTDEL_LOCKB_1_FIELD    0
+#define STV090x_WIDTH_SPKTDEL_LOCKB_1_FIELD    1
+
+#define STV090x_IRQSTATUS1                     0xf122
+#define STV090x_OFFST_SPKTDEL_LOCK_1_FIELD     7
+#define STV090x_WIDTH_SPKTDEL_LOCK_1_FIELD     1
+#define STV090x_OFFST_SDEMOD_LOCKB_2_FIELD     2
+#define STV090x_WIDTH_SDEMOD_LOCKB_2_FIELD     1
+#define STV090x_OFFST_SDEMOD_LOCK_2_FIELD      1
+#define STV090x_WIDTH_SDEMOD_LOCK_2_FIELD      1
+#define STV090x_OFFST_SDEMOD_IRQ_2_FIELD       0
+#define STV090x_WIDTH_SDEMOD_IRQ_2_FIELD       1
+
+#define STV090x_IRQSTATUS0                     0xf123
+#define STV090x_OFFST_SDEMOD_LOCKB_1_FIELD     7
+#define STV090x_WIDTH_SDEMOD_LOCKB_1_FIELD     1
+#define STV090x_OFFST_SDEMOD_LOCK_1_FIELD      6
+#define STV090x_WIDTH_SDEMOD_LOCK_1_FIELD      1
+#define STV090x_OFFST_SDEMOD_IRQ_1_FIELD       5
+#define STV090x_WIDTH_SDEMOD_IRQ_1_FIELD       1
+#define STV090x_OFFST_SBCH_ERRFLAG_FIELD       4
+#define STV090x_WIDTH_SBCH_ERRFLAG_FIELD       1
+#define STV090x_OFFST_SDISEQC2RX_IRQ_FIELD     3
+#define STV090x_WIDTH_SDISEQC2RX_IRQ_FIELD     1
+#define STV090x_OFFST_SDISEQC2TX_IRQ_FIELD     2
+#define STV090x_WIDTH_SDISEQC2TX_IRQ_FIELD     1
+#define STV090x_OFFST_SDISEQC1RX_IRQ_FIELD     1
+#define STV090x_WIDTH_SDISEQC1RX_IRQ_FIELD     1
+#define STV090x_OFFST_SDISEQC1TX_IRQ_FIELD     0
+#define STV090x_WIDTH_SDISEQC1TX_IRQ_FIELD     1
+
+#define STV090x_IRQMASK3                       0xf124
+#define STV090x_OFFST_MPLL_LOCK_FIELD          5
+#define STV090x_WIDTH_MPLL_LOCK_FIELD          1
+#define STV090x_OFFST_MSTREAM_LCK_3_FIELD      2
+#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD      3
+#define STV090x_OFFST_MSTREAM_LCK_2_FIELD      2
+#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD      3
+#define STV090x_OFFST_MSTREAM_LCK_1_FIELD      2
+#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD      3
+#define STV090x_OFFST_MDVBS1_PRF_2_FIELD       1
+#define STV090x_WIDTH_MDVBS1_PRF_2_FIELD       1
+#define STV090x_OFFST_MDVBS1_PRF_1_FIELD       0
+#define STV090x_WIDTH_MDVBS1_PRF_1_FIELD       1
+
+#define STV090x_IRQMASK2                       0xf125
+#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD      5
+#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD      3
+#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD      5
+#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD      3
+#define STV090x_OFFST_MSPY_ENDSIM_1_FIELD      5
+#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD      3
+#define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD    4
+#define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD    1
+#define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD    3
+#define STV090x_WIDTH_MPKTDEL_LOCKB_2_FIELD    1
+#define STV090x_OFFST_MPKTDEL_LOCK_2_FIELD     2
+#define STV090x_WIDTH_MPKTDEL_LOCK_2_FIELD     1
+#define STV090x_OFFST_MPKTDEL_ERROR_1_FIELD    1
+#define STV090x_WIDTH_MPKTDEL_ERROR_1_FIELD    1
+#define STV090x_OFFST_MPKTDEL_LOCKB_1_FIELD    0
+#define STV090x_WIDTH_MPKTDEL_LOCKB_1_FIELD    1
+
+#define STV090x_IRQMASK1                       0xf126
+#define STV090x_OFFST_MPKTDEL_LOCK_1_FIELD     7
+#define STV090x_WIDTH_MPKTDEL_LOCK_1_FIELD     1
+#define STV090x_OFFST_MEXTPINB2_FIELD          6
+#define STV090x_WIDTH_MEXTPINB2_FIELD          1
+#define STV090x_OFFST_MEXTPIN2_FIELD           5
+#define STV090x_WIDTH_MEXTPIN2_FIELD           1
+#define STV090x_OFFST_MEXTPINB1_FIELD          4
+#define STV090x_WIDTH_MEXTPINB1_FIELD          1
+#define STV090x_OFFST_MEXTPIN1_FIELD           3
+#define STV090x_WIDTH_MEXTPIN1_FIELD           1
+#define STV090x_OFFST_MDEMOD_LOCKB_2_FIELD     2
+#define STV090x_WIDTH_MDEMOD_LOCKB_2_FIELD     1
+#define STV090x_OFFST_MDEMOD_LOCK_2_FIELD      1
+#define STV090x_WIDTH_MDEMOD_LOCK_2_FIELD      1
+#define STV090x_OFFST_MDEMOD_IRQ_2_FIELD       0
+#define STV090x_WIDTH_MDEMOD_IRQ_2_FIELD       1
+
+#define STV090x_IRQMASK0                       0xf127
+#define STV090x_OFFST_MDEMOD_LOCKB_1_FIELD     7
+#define STV090x_WIDTH_MDEMOD_LOCKB_1_FIELD     1
+#define STV090x_OFFST_MDEMOD_LOCK_1_FIELD      6
+#define STV090x_WIDTH_MDEMOD_LOCK_1_FIELD      1
+#define STV090x_OFFST_MDEMOD_IRQ_1_FIELD       5
+#define STV090x_WIDTH_MDEMOD_IRQ_1_FIELD       1
+#define STV090x_OFFST_MBCH_ERRFLAG_FIELD       4
+#define STV090x_WIDTH_MBCH_ERRFLAG_FIELD       1
+#define STV090x_OFFST_MDISEQC2RX_IRQ_FIELD     3
+#define STV090x_WIDTH_MDISEQC2RX_IRQ_FIELD     1
+#define STV090x_OFFST_MDISEQC2TX_IRQ_FIELD     2
+#define STV090x_WIDTH_MDISEQC2TX_IRQ_FIELD     1
+#define STV090x_OFFST_MDISEQC1RX_IRQ_FIELD     1
+#define STV090x_WIDTH_MDISEQC1RX_IRQ_FIELD     1
+#define STV090x_OFFST_MDISEQC1TX_IRQ_FIELD     0
+#define STV090x_WIDTH_MDISEQC1TX_IRQ_FIELD     1
+
+#define STV090x_I2CCFG                         0xf129
+#define STV090x_OFFST_12C_FASTMODE_FIELD       3
+#define STV090x_WIDTH_12C_FASTMODE_FIELD       1
+#define STV090x_OFFST_12CADDR_INC_FIELD                0
+#define STV090x_WIDTH_12CADDR_INC_FIELD                2
+
+#define STV090x_Px_I2CRPT(__x)                 (0xf12a + (__x - 1) * 0x1)
+#define STV090x_P1_I2CRPT                      STV090x_Px_I2CRPT(1)
+#define STV090x_P2_I2CRPT                      STV090x_Px_I2CRPT(2)
+#define STV090x_OFFST_Px_I2CT_ON_FIELD         7
+#define STV090x_WIDTH_Px_I2CT_ON_FIELD         1
+#define STV090x_OFFST_Px_ENARPT_LEVEL_FIELD    4
+#define STV090x_WIDTH_Px_ENARPT_LEVEL_FIELD    3
+#define STV090x_OFFST_Px_SCLT_DELAY_FIELD      3
+#define STV090x_WIDTH_Px_SCLT_DELAY_FIELD      1
+#define STV090x_OFFST_Px_STOP_ENABLE_FIELD     2
+#define STV090x_WIDTH_Px_STOP_ENABLE_FIELD     1
+#define STV090x_OFFST_Px_STOP_SDAT2SDA_FIELD   1
+#define STV090x_WIDTH_Px_STOP_SDAT2SDA_FIELD   1
+
+#define STV090x_CLKI2CFG                       0xf140
+#define STV090x_OFFST_CLKI2_OPD_FIELD          7
+#define STV090x_WIDTH_CLKI2_OPD_FIELD          1
+#define STV090x_OFFST_CLKI2_CONFIG_FIELD       1
+#define STV090x_WIDTH_CLKI2_CONFIG_FIELD       6
+#define STV090x_OFFST_CLKI2_XOR_FIELD          0
+#define STV090x_WIDTH_CLKI2_XOR_FIELD          1
+
+#define STV090x_GPIOxCFG(__x)                  (0xf141 + (__x - 1))
+#define STV090x_GPIO1CFG                       STV090x_GPIOxCFG(1)
+#define STV090x_GPIO2CFG                       STV090x_GPIOxCFG(2)
+#define STV090x_GPIO3CFG                       STV090x_GPIOxCFG(3)
+#define STV090x_GPIO4CFG                       STV090x_GPIOxCFG(4)
+#define STV090x_GPIO5CFG                       STV090x_GPIOxCFG(5)
+#define STV090x_GPIO6CFG                       STV090x_GPIOxCFG(6)
+#define STV090x_GPIO7CFG                       STV090x_GPIOxCFG(7)
+#define STV090x_GPIO8CFG                       STV090x_GPIOxCFG(8)
+#define STV090x_GPIO9CFG                       STV090x_GPIOxCFG(9)
+#define STV090x_GPIO10CFG                      STV090x_GPIOxCFG(10)
+#define STV090x_GPIO11CFG                      STV090x_GPIOxCFG(11)
+#define STV090x_GPIO12CFG                      STV090x_GPIOxCFG(12)
+#define STV090x_GPIO13CFG                      STV090x_GPIOxCFG(13)
+#define STV090x_OFFST_GPIOx_OPD_FIELD          7
+#define STV090x_WIDTH_GPIOx_OPD_FIELD          1
+#define STV090x_OFFST_GPIOx_CONFIG_FIELD       1
+#define STV090x_WIDTH_GPIOx_CONFIG_FIELD       6
+#define STV090x_OFFST_GPIOx_XOR_FIELD          0
+#define STV090x_WIDTH_GPIOx_XOR_FIELD          1
+
+#define STV090x_CSxCFG(__x)                    (0xf14e + __x * 0x1)
+#define STV090x_CS0CFG                         STV090x_CSxCFG(0)
+#define STV090x_CS1CFG                         STV090x_CSxCFG(1)
+#define STV090x_OFFST_CSX_OPD_FIELD            7
+#define STV090x_WIDTH_CSX_OPD_FIELD            1
+#define STV090x_OFFST_CSX_CONFIG_FIELD         1
+#define STV090x_WIDTH_CSX_CONFIG_FIELD         6
+#define STV090x_OFFST_CSX_XOR_FIELD            0
+#define STV090x_WIDTH_CSX_XOR_FIELD            1
+
+
+#define STV090x_STDBYCFG                       0xf150
+#define STV090x_OFFST_STDBY_OPD_FIELD          7
+#define STV090x_WIDTH_STDBY_OPD_FIELD          1
+#define STV090x_OFFST_STDBY_CONFIG_FIELD       1
+#define STV090x_WIDTH_STDBY_CONFIG_FIELD       6
+#define STV090x_OFFST_STDBY_XOR_FIELD          0
+#define STV090x_WIDTH_STDBY_XOR_FIELD          1
+
+#define STV090x_DIRCLKCFG                      0xf151
+#define STV090x_OFFST_DIRCLK_OPD_FIELD         7
+#define STV090x_WIDTH_DIRCLK_OPD_FIELD         1
+#define STV090x_OFFST_DIRCLK_CONFIG_FIELD      1
+#define STV090x_WIDTH_DIRCLK_CONFIG_FIELD      6
+#define STV090x_OFFST_DIRCLK_XOR_FIELD         0
+#define STV090x_WIDTH_DIRCLK_XOR_FIELD         1
+
+
+#define STV090x_AGCRFxCFG(__x)                 (0xf152 + (__x - 1) * 0x4)
+#define STV090x_AGCRF1CFG                      STV090x_AGCRFxCFG(1)
+#define STV090x_AGCRF2CFG                      STV090x_AGCRFxCFG(2)
+#define STV090x_OFFST_AGCRFx_OPD_FIELD         7
+#define STV090x_WIDTH_AGCRFx_OPD_FIELD         1
+#define STV090x_OFFST_AGCRFx_CONFIG_FIELD      1
+#define STV090x_WIDTH_AGCRFx_CONFIG_FIELD      6
+#define STV090x_OFFST_AGCRFx_XOR_FIELD         0
+#define STV090x_WIDTH_AGCRFx_XOR_FIELD         1
+
+#define STV090x_SDATxCFG(__x)                  (0xf153 + (__x - 1) * 0x4)
+#define STV090x_SDAT1CFG                       STV090x_SDATxCFG(1)
+#define STV090x_SDAT2CFG                       STV090x_SDATxCFG(2)
+#define STV090x_OFFST_SDATx_OPD_FIELD          7
+#define STV090x_WIDTH_SDATx_OPD_FIELD          1
+#define STV090x_OFFST_SDATx_CONFIG_FIELD       1
+#define STV090x_WIDTH_SDATx_CONFIG_FIELD       6
+#define STV090x_OFFST_SDATx_XOR_FIELD          0
+#define STV090x_WIDTH_SDATx_XOR_FIELD          1
+
+#define STV090x_SCLTxCFG(__x)                  (0xf154 + (__x - 1) * 0x4)
+#define STV090x_SCLT1CFG                       STV090x_SCLTxCFG(1)
+#define STV090x_SCLT2CFG                       STV090x_SCLTxCFG(2)
+#define STV090x_OFFST_SCLTx_OPD_FIELD          7
+#define STV090x_WIDTH_SCLTx_OPD_FIELD          1
+#define STV090x_OFFST_SCLTx_CONFIG_FIELD       1
+#define STV090x_WIDTH_SCLTx_CONFIG_FIELD       6
+#define STV090x_OFFST_SCLTx_XOR_FIELD          0
+#define STV090x_WIDTH_SCLTx_XOR_FIELD          1
+
+#define STV090x_DISEQCOxCFG(__x)               (0xf155 + (__x - 1) * 0x4)
+#define STV090x_DISEQCO1CFG                    STV090x_DISEQCOxCFG(1)
+#define STV090x_DISEQCO2CFG                    STV090x_DISEQCOxCFG(2)
+#define STV090x_OFFST_DISEQCOx_OPD_FIELD       7
+#define STV090x_WIDTH_DISEQCOx_OPD_FIELD       1
+#define STV090x_OFFST_DISEQCOx_CONFIG_FIELD    1
+#define STV090x_WIDTH_DISEQCOx_CONFIG_FIELD    6
+#define STV090x_OFFST_DISEQCOx_XOR_FIELD       0
+#define STV090x_WIDTH_DISEQCOx_XOR_FIELD       1
+
+#define STV090x_CLKOUT27CFG                    0xf15a
+#define STV090x_OFFST_CLKOUT27_OPD_FIELD       7
+#define STV090x_WIDTH_CLKOUT27_OPD_FIELD       1
+#define STV090x_OFFST_CLKOUT27_CONFIG_FIELD    1
+#define STV090x_WIDTH_CLKOUT27_CONFIG_FIELD    6
+#define STV090x_OFFST_CLKOUT27_XOR_FIELD       0
+#define STV090x_WIDTH_CLKOUT27_XOR_FIELD       1
+
+#define STV090x_ERRORxCFG(__x)                 (0xf15b + (__x - 1) * 0x5)
+#define STV090x_ERROR1CFG                      STV090x_ERRORxCFG(1)
+#define STV090x_ERROR2CFG                      STV090x_ERRORxCFG(2)
+#define STV090x_ERROR3CFG                      STV090x_ERRORxCFG(3)
+#define STV090x_OFFST_ERRORx_OPD_FIELD         7
+#define STV090x_WIDTH_ERRORx_OPD_FIELD         1
+#define STV090x_OFFST_ERRORx_CONFIG_FIELD      1
+#define STV090x_WIDTH_ERRORx_CONFIG_FIELD      6
+#define STV090x_OFFST_ERRORx_XOR_FIELD         0
+#define STV090x_WIDTH_ERRORx_XOR_FIELD         1
+
+#define STV090x_DPNxCFG(__x)                   (0xf15c + (__x - 1) * 0x5)
+#define STV090x_DPN1CFG                                STV090x_DPNxCFG(1)
+#define STV090x_DPN2CFG                                STV090x_DPNxCFG(2)
+#define STV090x_DPN3CFG                                STV090x_DPNxCFG(3)
+#define STV090x_OFFST_DPNx_OPD_FIELD           7
+#define STV090x_WIDTH_DPNx_OPD_FIELD           1
+#define STV090x_OFFST_DPNx_CONFIG_FIELD                1
+#define STV090x_WIDTH_DPNx_CONFIG_FIELD                6
+#define STV090x_OFFST_DPNx_XOR_FIELD           0
+#define STV090x_WIDTH_DPNx_XOR_FIELD           1
+
+#define STV090x_STROUTxCFG(__x)                        (0xf15d + (__x - 1) * 0x5)
+#define STV090x_STROUT1CFG                     STV090x_STROUTxCFG(1)
+#define STV090x_STROUT2CFG                     STV090x_STROUTxCFG(2)
+#define STV090x_STROUT3CFG                     STV090x_STROUTxCFG(3)
+#define STV090x_OFFST_STROUTx_OPD_FIELD                7
+#define STV090x_WIDTH_STROUTx_OPD_FIELD                1
+#define STV090x_OFFST_STROUTx_CONFIG_FIELD     1
+#define STV090x_WIDTH_STROUTx_CONFIG_FIELD     6
+#define STV090x_OFFST_STROUTx_XOR_FIELD                0
+#define STV090x_WIDTH_STROUTx_XOR_FIELD                1
+
+#define STV090x_CLKOUTxCFG(__x)                        (0xf15e + (__x - 1) * 0x5)
+#define STV090x_CLKOUT1CFG                     STV090x_CLKOUTxCFG(1)
+#define STV090x_CLKOUT2CFG                     STV090x_CLKOUTxCFG(2)
+#define STV090x_CLKOUT3CFG                     STV090x_CLKOUTxCFG(3)
+#define STV090x_OFFST_CLKOUTx_OPD_FIELD                7
+#define STV090x_WIDTH_CLKOUTx_OPD_FIELD                1
+#define STV090x_OFFST_CLKOUTx_CONFIG_FIELD     1
+#define STV090x_WIDTH_CLKOUTx_CONFIG_FIELD     6
+#define STV090x_OFFST_CLKOUTx_XOR_FIELD                0
+#define STV090x_WIDTH_CLKOUTx_XOR_FIELD                1
+
+#define STV090x_DATAxCFG(__x)                  (0xf15f + (__x - 71) * 0x5)
+#define STV090x_DATA71CFG                      STV090x_DATAxCFG(71)
+#define STV090x_DATA72CFG                      STV090x_DATAxCFG(72)
+#define STV090x_DATA73CFG                      STV090x_DATAxCFG(73)
+#define STV090x_OFFST_DATAx_OPD_FIELD          7
+#define STV090x_WIDTH_DATAx_OPD_FIELD          1
+#define STV090x_OFFST_DATAx_CONFIG_FIELD       1
+#define STV090x_WIDTH_DATAx_CONFIG_FIELD       6
+#define STV090x_OFFST_DATAx_XOR_FIELD          0
+#define STV090x_WIDTH_DATAx_XOR_FIELD          1
+
+#define STV090x_NCOARSE                                0xf1b3
+#define STV090x_OFFST_M_DIV_FIELD              0
+#define STV090x_WIDTH_M_DIV_FIELD              8
+
+#define STV090x_SYNTCTRL                       0xf1b6
+#define STV090x_OFFST_STANDBY_FIELD            7
+#define STV090x_WIDTH_STANDBY_FIELD            1
+#define STV090x_OFFST_BYPASSPLLCORE_FIELD      6
+#define STV090x_WIDTH_BYPASSPLLCORE_FIELD      1
+#define STV090x_OFFST_SELX1RATIO_FIELD         5
+#define STV090x_WIDTH_SELX1RATIO_FIELD         1
+#define STV090x_OFFST_STOP_PLL_FIELD           3
+#define STV090x_WIDTH_SELX1RATIO_FIELD         1
+#define STV090x_OFFST_BYPASSPLLFSK_FIELD       2
+#define STV090x_WIDTH_BYPASSPLLFSK_FIELD       1
+#define STV090x_OFFST_SELOSCI_FIELD            1
+#define STV090x_WIDTH_SELOSCI_FIELD            1
+#define STV090x_OFFST_BYPASSPLLADC_FIELD       0
+#define STV090x_WIDTH_BYPASSPLLADC_FIELD       1
+
+#define STV090x_FILTCTRL                       0xf1b7
+#define STV090x_OFFST_INV_CLK135_FIELD         7
+#define STV090x_WIDTH_INV_CLK135_FIELD         1
+#define STV090x_OFFST_SEL_FSKCKDIV_FIELD       2
+#define STV090x_WIDTH_SEL_FSKCKDIV_FIELD       1
+#define STV090x_OFFST_INV_CLKFSK_FIELD         1
+#define STV090x_WIDTH_INV_CLKFSK_FIELD         1
+#define STV090x_OFFST_BYPASS_APPLI_FIELD       0
+#define STV090x_WIDTH_BYPASS_APPLI_FIELD       1
+
+#define STV090x_PLLSTAT                                0xf1b8
+#define STV090x_OFFST_PLLLOCK_FIELD            0
+#define STV090x_WIDTH_PLLLOCK_FIELD            1
+
+#define STV090x_STOPCLK1                       0xf1c2
+#define STV090x_OFFST_STOP_CLKPKDT2_FIELD      6
+#define STV090x_WIDTH_STOP_CLKPKDT2_FIELD      1
+#define STV090x_OFFST_STOP_CLKPKDT1_FIELD      5
+#define STV090x_WIDTH_STOP_CLKPKDT1_FIELD      1
+#define STV090x_OFFST_STOP_CLKFEC_FIELD                4
+#define STV090x_WIDTH_STOP_CLKFEC_FIELD                1
+#define STV090x_OFFST_STOP_CLKADCI2_FIELD      3
+#define STV090x_WIDTH_STOP_CLKADCI2_FIELD      1
+#define STV090x_OFFST_INV_CLKADCI2_FIELD       2
+#define STV090x_WIDTH_INV_CLKADCI2_FIELD       1
+#define STV090x_OFFST_STOP_CLKADCI1_FIELD      1
+#define STV090x_WIDTH_STOP_CLKADCI1_FIELD      1
+#define STV090x_OFFST_INV_CLKADCI1_FIELD       0
+#define STV090x_WIDTH_INV_CLKADCI1_FIELD       1
+
+#define STV090x_STOPCLK2                       0xf1c3
+#define STV090x_OFFST_STOP_CLKSAMP2_FIELD      4
+#define STV090x_WIDTH_STOP_CLKSAMP2_FIELD      1
+#define STV090x_OFFST_STOP_CLKSAMP1_FIELD      3
+#define STV090x_WIDTH_STOP_CLKSAMP1_FIELD      1
+#define STV090x_OFFST_STOP_CLKVIT2_FIELD       2
+#define STV090x_WIDTH_STOP_CLKVIT2_FIELD       1
+#define STV090x_OFFST_STOP_CLKVIT1_FIELD       1
+#define STV090x_WIDTH_STOP_CLKVIT1_FIELD       1
+#define STV090x_OFFST_STOP_CLKTS_FIELD         0
+#define STV090x_WIDTH_STOP_CLKTS_FIELD         1
+
+#define STV090x_TSTTNR0                                0xf1df
+#define STV090x_OFFST_SEL_FSK_FIELD            7
+#define STV090x_WIDTH_SEL_FSK_FIELD            1
+#define STV090x_OFFST_FSK_PON_FIELD            2
+#define STV090x_WIDTH_FSK_PON_FIELD            1
+
+#define STV090x_TSTTNR1                                0xf1e0
+#define STV090x_OFFST_ADC1_PON_FIELD           1
+#define STV090x_WIDTH_ADC1_PON_FIELD           1
+#define STV090x_OFFST_ADC1_INMODE_FIELD                0
+#define STV090x_WIDTH_ADC1_INMODE_FIELD                1
+
+#define STV090x_TSTTNR2                                0xf1e1
+#define STV090x_OFFST_DISEQC1_PON_FIELD                5
+#define STV090x_WIDTH_DISEQC1_PON_FIELD                1
+
+#define STV090x_TSTTNR3                                0xf1e2
+#define STV090x_OFFST_ADC2_PON_FIELD           1
+#define STV090x_WIDTH_ADC2_PON_FIELD           1
+#define STV090x_OFFST_ADC2_INMODE_FIELD                0
+#define STV090x_WIDTH_ADC2_INMODE_FIELD                1
+
+#define STV090x_TSTTNR4                                0xf1e3
+#define STV090x_OFFST_DISEQC2_PON_FIELD                5
+#define STV090x_WIDTH_DISEQC2_PON_FIELD                1
+
+#define STV090x_FSKTFC2                                0xf170
+#define STV090x_OFFST_FSKT_KMOD_FIELD          2
+#define STV090x_WIDTH_FSKT_KMOD_FIELD          6
+#define STV090x_OFFST_FSKT_CAR_FIELD           0
+#define STV090x_WIDTH_FSKT_CAR_FIELD           2
+
+#define STV090x_FSKTFC1                                0xf171
+#define STV090x_OFFST_FSKTC1_CAR_FIELD         0
+#define STV090x_WIDTH_FSKTC1_CAR_FIELD         8
+
+#define STV090x_FSKTFC0                                0xf172
+#define STV090x_OFFST_FSKTC0_CAR_FIELD         0
+#define STV090x_WIDTH_FSKTC0_CAR_FIELD         8
+
+#define STV090x_FSKTDELTAF1                    0xf173
+#define STV090x_OFFST_FSKTF1_DELTAF_FIELD      0
+#define STV090x_WIDTH_FSKTF1_DELTAF_FIELD      4
+
+#define STV090x_FSKTDELTAF0                    0xf174
+#define STV090x_OFFST_FSKTF0_DELTAF_FIELD      0
+#define STV090x_WIDTH_FSKTF0_DELTAF_FIELD      8
+
+#define STV090x_FSKTCTRL                       0xf175
+#define STV090x_OFFST_FSKT_EN_SGN_FIELD                6
+#define STV090x_WIDTH_FSKT_EN_SGN_FIELD                1
+#define STV090x_OFFST_FSKT_MOD_SGN_FIELD       5
+#define STV090x_WIDTH_FSKT_MOD_SGN_FIELD       1
+#define STV090x_OFFST_FSKT_MOD_EN_FIELD                2
+#define STV090x_WIDTH_FSKT_MOD_EN_FIELD                3
+#define STV090x_OFFST_FSKT_DACMODE_FIELD       0
+#define STV090x_WIDTH_FSKT_DACMODE_FIELD       2
+
+#define STV090x_FSKRFC2                                0xf176
+#define STV090x_OFFST_FSKRC2_DETSGN_FIELD      6
+#define STV090x_WIDTH_FSKRC2_DETSGN_FIELD      1
+#define STV090x_OFFST_FSKRC2_OUTSGN_FIELD      5
+#define STV090x_WIDTH_FSKRC2_OUTSGN_FIELD      1
+#define STV090x_OFFST_FSKRC2_KAGC_FIELD                2
+#define STV090x_WIDTH_FSKRC2_KAGC_FIELD                3
+#define STV090x_OFFST_FSKRC2_CAR_FIELD         0
+#define STV090x_WIDTH_FSKRC2_CAR_FIELD         2
+
+#define STV090x_FSKRFC1                                0xf177
+#define STV090x_OFFST_FSKRC1_CAR_FIELD         0
+#define STV090x_WIDTH_FSKRC1_CAR_FIELD         8
+
+#define STV090x_FSKRFC0                                0xf178
+#define STV090x_OFFST_FSKRC0_CAR_FIELD         0
+#define STV090x_WIDTH_FSKRC0_CAR_FIELD         8
+
+#define STV090x_FSKRK1                         0xf179
+#define STV090x_OFFST_FSKR_K1_EXP_FIELD                5
+#define STV090x_WIDTH_FSKR_K1_EXP_FIELD                3
+#define STV090x_OFFST_FSKR_K1_MANT_FIELD       0
+#define STV090x_WIDTH_FSKR_K1_MANT_FIELD       5
+
+#define STV090x_FSKRK2                         0xf17a
+#define STV090x_OFFST_FSKR_K2_EXP_FIELD                5
+#define STV090x_WIDTH_FSKR_K2_EXP_FIELD                3
+#define STV090x_OFFST_FSKR_K2_MANT_FIELD       0
+#define STV090x_WIDTH_FSKR_K2_MANT_FIELD       5
+
+#define STV090x_FSKRAGCR                       0xf17b
+#define STV090x_OFFST_FSKR_OUTCTL_FIELD                6
+#define STV090x_WIDTH_FSKR_OUTCTL_FIELD                2
+#define STV090x_OFFST_FSKR_AGC_REF_FIELD       0
+#define STV090x_WIDTH_FSKR_AGC_REF_FIELD       6
+
+#define STV090x_FSKRAGC                                0xf17c
+#define STV090x_OFFST_FSKR_AGC_ACCU_FIELD      0
+#define STV090x_WIDTH_FSKR_AGC_ACCU_FIELD      8
+
+#define STV090x_FSKRALPHA                      0xf17d
+#define STV090x_OFFST_FSKR_ALPHA_EXP_FIELD     2
+#define STV090x_WIDTH_FSKR_ALPHA_EXP_FIELD     3
+#define STV090x_OFFST_FSKR_ALPHA_M_FIELD       0
+#define STV090x_WIDTH_FSKR_ALPHA_M_FIELD       2
+
+#define STV090x_FSKRPLTH1                      0xf17e
+#define STV090x_OFFST_FSKR_BETA_FIELD          4
+#define STV090x_WIDTH_FSKR_BETA_FIELD          4
+#define STV090x_OFFST_FSKR_PLL_TRESH1_FIELD    0
+#define STV090x_WIDTH_FSKR_PLL_TRESH1_FIELD    4
+
+#define STV090x_FSKRPLTH0                      0xf17f
+#define STV090x_OFFST_FSKR_PLL_TRESH0_FIELD    0
+#define STV090x_WIDTH_FSKR_PLL_TRESH0_FIELD    8
+
+#define STV090x_FSKRDF1                                0xf180
+#define STV090x_OFFST_FSKR_DELTAF1_FIELD       0
+#define STV090x_WIDTH_FSKR_DELTAF1_FIELD       5
+
+#define STV090x_FSKRDF0                                0xf181
+#define STV090x_OFFST_FSKR_DELTAF0_FIELD       0
+#define STV090x_WIDTH_FSKR_DELTAF0_FIELD       8
+
+#define STV090x_FSKRSTEPP                      0xf182
+#define STV090x_OFFST_FSKR_STEP_PLUS_FIELD     0
+#define STV090x_WIDTH_FSKR_STEP_PLUS_FIELD     8
+
+#define STV090x_FSKRSTEPM                      0xf183
+#define STV090x_OFFST_FSKR_STEP_MINUS_FIELD    0
+#define STV090x_WIDTH_FSKR_STEP_MINUS_FIELD    8
+
+#define STV090x_FSKRDET1                       0xf184
+#define STV090x_OFFST_FSKR_CARDET1_ACCU_FIELD  0
+#define STV090x_WIDTH_FSKR_CARDET1_ACCU_FIELD  4
+
+#define STV090x_FSKRDET0                       0xf185
+#define STV090x_OFFST_FSKR_CARDET0_ACCU_FIELD  0
+#define STV090x_WIDTH_FSKR_CARDET0_ACCU_FIELD  8
+
+#define STV090x_FSKRDTH1                               0xf186
+#define STV090x_OFFST_FSKR_CARLOSS_THRESH1_FIELD       4
+#define STV090x_WIDTH_FSKR_CARLOSS_THRESH1_FIELD       4
+#define STV090x_OFFST_FSKR_CARDET_THRESH1_FIELD                0
+#define STV090x_WIDTH_FSKR_CARDET_THRESH1_FIELD                4
+
+#define STV090x_FSKRDTH0                       0xf187
+#define STV090x_OFFST_FSKR_CARDET_THRESH0_FIELD        0
+#define STV090x_WIDTH_FSKR_CARDET_THRESH0_FIELD        8
+
+#define STV090x_FSKRLOSS                       0xf188
+#define STV090x_OFFST_FSKR_CARLOSS_THRESH_FIELD        0
+#define STV090x_WIDTH_FSKR_CARLOSS_THRESH_FIELD        8
+
+#define STV090x_Px_DISTXCTL(__x)               (0xF1A0 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXCTL                    STV090x_Px_DISTXCTL(1)
+#define STV090x_P2_DISTXCTL                    STV090x_Px_DISTXCTL(2)
+#define STV090x_OFFST_Px_TIM_OFF_FIELD         7
+#define STV090x_WIDTH_Px_TIM_OFF_FIELD         1
+#define STV090x_OFFST_Px_DISEQC_RESET_FIELD    6
+#define STV090x_WIDTH_Px_DISEQC_RESET_FIELD    1
+#define STV090x_OFFST_Px_TIM_CMD_FIELD         4
+#define STV090x_WIDTH_Px_TIM_CMD_FIELD         2
+#define STV090x_OFFST_Px_DIS_PRECHARGE_FIELD   3
+#define STV090x_WIDTH_Px_DIS_PRECHARGE_FIELD   1
+#define STV090x_OFFST_Px_DISTX_MODE_FIELD      0
+#define STV090x_WIDTH_Px_DISTX_MODE_FIELD      3
+
+#define STV090x_Px_DISRXCTL(__x)               (0xf1a1 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRXCTL                    STV090x_Px_DISRXCTL(1)
+#define STV090x_P2_DISRXCTL                    STV090x_Px_DISRXCTL(2)
+#define STV090x_OFFST_Px_RECEIVER_ON_FIELD     7
+#define STV090x_WIDTH_Px_RECEIVER_ON_FIELD     1
+#define STV090x_OFFST_Px_IGNO_SHORT22K_FIELD   6
+#define STV090x_WIDTH_Px_IGNO_SHORT22K_FIELD   1
+#define STV090x_OFFST_Px_ONECHIP_TRX_FIELD     5
+#define STV090x_WIDTH_Px_ONECHIP_TRX_FIELD     1
+#define STV090x_OFFST_Px_EXT_ENVELOP_FIELD     4
+#define STV090x_WIDTH_Px_EXT_ENVELOP_FIELD     1
+#define STV090x_OFFST_Px_PIN_SELECT_FIELD      2
+#define STV090x_WIDTH_Px_PIN_SELECT_FIELD      2
+#define STV090x_OFFST_Px_IRQ_RXEND_FIELD       1
+#define STV090x_WIDTH_Px_IRQ_RXEND_FIELD       1
+#define STV090x_OFFST_Px_IRQ_4NBYTES_FIELD     0
+#define STV090x_WIDTH_Px_IRQ_4NBYTES_FIELD     1
+
+#define STV090x_Px_DISRX_ST0(__x)              (0xf1a4 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRX_ST0                   STV090x_Px_DISRX_ST0(1)
+#define STV090x_P2_DISRX_ST0                   STV090x_Px_DISRX_ST0(2)
+#define STV090x_OFFST_Px_RX_END_FIELD          7
+#define STV090x_WIDTH_Px_RX_END_FIELD          1
+#define STV090x_OFFST_Px_RX_ACTIVE_FIELD       6
+#define STV090x_WIDTH_Px_RX_ACTIVE_FIELD       1
+#define STV090x_OFFST_Px_SHORT_22KHZ_FIELD     5
+#define STV090x_WIDTH_Px_SHORT_22KHZ_FIELD     1
+#define STV090x_OFFST_Px_CONT_TONE_FIELD       4
+#define STV090x_WIDTH_Px_CONT_TONE_FIELD       1
+#define STV090x_OFFST_Px_FIFO_4BREADY_FIELD    3
+#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD    2
+#define STV090x_OFFST_Px_FIFO_EMPTY_FIELD      2
+#define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD      1
+#define STV090x_OFFST_Px_ABORT_DISRX_FIELD     0
+#define STV090x_WIDTH_Px_ABORT_DISRX_FIELD     1
+
+#define STV090x_Px_DISRX_ST1(__x)              (0xf1a5 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRX_ST1                   STV090x_Px_DISRX_ST1(1)
+#define STV090x_P2_DISRX_ST1                   STV090x_Px_DISRX_ST1(2)
+#define STV090x_OFFST_Px_RX_FAIL_FIELD         7
+#define STV090x_WIDTH_Px_RX_FAIL_FIELD         1
+#define STV090x_OFFST_Px_FIFO_PARITYFAIL_FIELD 6
+#define STV090x_WIDTH_Px_FIFO_PARITYFAIL_FIELD 1
+#define STV090x_OFFST_Px_RX_NONBYTE_FIELD      5
+#define STV090x_WIDTH_Px_RX_NONBYTE_FIELD      1
+#define STV090x_OFFST_Px_FIFO_OVERFLOW_FIELD   4
+#define STV090x_WIDTH_Px_FIFO_OVERFLOW_FIELD   1
+#define STV090x_OFFST_Px_FIFO_BYTENBR_FIELD    0
+#define STV090x_WIDTH_Px_FIFO_BYTENBR_FIELD    4
+
+#define STV090x_Px_DISRXDATA(__x)              (0xf1a6 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRXDATA                   STV090x_Px_DISRXDATA(1)
+#define STV090x_P2_DISRXDATA                   STV090x_Px_DISRXDATA(2)
+#define STV090x_OFFST_Px_DISRX_DATA_FIELD      0
+#define STV090x_WIDTH_Px_DISRX_DATA_FIELD      8
+
+#define STV090x_Px_DISTXDATA(__x)              (0xf1a7 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXDATA                   STV090x_Px_DISTXDATA(1)
+#define STV090x_P2_DISTXDATA                   STV090x_Px_DISTXDATA(2)
+#define STV090x_OFFST_Px_DISEQC_FIFO_FIELD     0
+#define STV090x_WIDTH_Px_DISEQC_FIFO_FIELD     8
+
+#define STV090x_Px_DISTXSTATUS(__x)            (0xf1a8 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXSTATUS                 STV090x_Px_DISTXSTATUS(1)
+#define STV090x_P2_DISTXSTATUS                 STV090x_Px_DISTXSTATUS(2)
+#define STV090x_OFFST_Px_TX_FAIL_FIELD         7
+#define STV090x_WIDTH_Px_TX_FAIL_FIELD         1
+#define STV090x_OFFST_Px_FIFO_FULL_FIELD       6
+#define STV090x_WIDTH_Px_FIFO_FULL_FIELD       1
+#define STV090x_OFFST_Px_TX_IDLE_FIELD         5
+#define STV090x_WIDTH_Px_TX_IDLE_FIELD         1
+#define STV090x_OFFST_Px_GAP_BURST_FIELD       4
+#define STV090x_WIDTH_Px_GAP_BURST_FIELD       1
+#define STV090x_OFFST_Px_TXFIFO_BYTES_FIELD    0
+#define STV090x_WIDTH_Px_TXFIFO_BYTES_FIELD    4
+
+#define STV090x_Px_F22TX(__x)                  (0xf1a9 - (__x - 1) * 0x10)
+#define STV090x_P1_F22TX                       STV090x_Px_F22TX(1)
+#define STV090x_P2_F22TX                       STV090x_Px_F22TX(2)
+#define STV090x_OFFST_Px_F22_REG_FIELD         0
+#define STV090x_WIDTH_Px_F22_REG_FIELD         8
+
+#define STV090x_Px_F22RX(__x)                  (0xf1aa - (__x - 1) * 0x10)
+#define STV090x_P1_F22RX                       STV090x_Px_F22RX(1)
+#define STV090x_P2_F22RX                       STV090x_Px_F22RX(2)
+#define STV090x_OFFST_Px_F22RX_REG_FIELD       0
+#define STV090x_WIDTH_Px_F22RX_REG_FIELD       8
+
+#define STV090x_Px_ACRPRESC(__x)               (0xf1ac - (__x - 1) * 0x10)
+#define STV090x_P1_ACRPRESC                    STV090x_Px_ACRPRESC(1)
+#define STV090x_P2_ACRPRESC                    STV090x_Px_ACRPRESC(2)
+#define STV090x_OFFST_Px_ACR_PRESC_FIELD       0
+#define STV090x_WIDTH_Px_ACR_PRESC_FIELD       3
+
+#define STV090x_Px_ACRDIV(__x)                 (0xf1ad - (__x - 1) * 0x10)
+#define STV090x_P1_ACRDIV                      STV090x_Px_ACRDIV(1)
+#define STV090x_P2_ACRDIV                      STV090x_Px_ACRDIV(2)
+#define STV090x_OFFST_Px_ACR_DIV_FIELD         0
+#define STV090x_WIDTH_Px_ACR_DIV_FIELD         8
+
+#define STV090x_Px_IQCONST(__x)                        (0xF400 - (__x - 1) * 0x200)
+#define STV090x_P1_IQCONST                     STV090x_Px_IQCONST(1)
+#define STV090x_P2_IQCONST                     STV090x_Px_IQCONST(2)
+#define STV090x_OFFST_Px_CONSTEL_SELECT_FIELD  5
+#define STV090x_WIDTH_Px_CONSTEL_SELECT_FIELD  2
+
+#define STV090x_Px_NOSCFG(__x)                 (0xF401 - (__x - 1) * 0x200)
+#define STV090x_P1_NOSCFG                      STV090x_Px_NOSCFG(1)
+#define STV090x_P2_NOSCFG                      STV090x_Px_NOSCFG(2)
+#define STV090x_OFFST_Px_NOSPLH_BETA_FIELD     3
+#define STV090x_WIDTH_Px_NOSPLH_BETA_FIELD     2
+#define STV090x_OFFST_Px_NOSDATA_BETA_FIELD    0
+#define STV090x_WIDTH_Px_NOSDATA_BETA_FIELD    3
+
+#define STV090x_Px_ISYMB(__x)                  (0xF402 - (__x - 1) * 0x200)
+#define STV090x_P1_ISYMB                       STV090x_Px_ISYMB(1)
+#define STV090x_P2_ISYMB                       STV090x_Px_ISYMB(2)
+#define STV090x_OFFST_Px_I_SYMBOL_FIELD                0
+#define STV090x_WIDTH_Px_I_SYMBOL_FIELD                8
+
+#define STV090x_Px_QSYMB(__x)                  (0xF403 - (__x - 1) * 0x200)
+#define STV090x_P1_QSYMB                       STV090x_Px_QSYMB(1)
+#define STV090x_P2_QSYMB                       STV090x_Px_QSYMB(2)
+#define STV090x_OFFST_Px_Q_SYMBOL_FIELD                0
+#define STV090x_WIDTH_Px_Q_SYMBOL_FIELD                8
+
+#define STV090x_Px_AGC1CFG(__x)                        (0xF404 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1CFG                     STV090x_Px_AGC1CFG(1)
+#define STV090x_P2_AGC1CFG                     STV090x_Px_AGC1CFG(2)
+#define STV090x_OFFST_Px_DC_FROZEN_FIELD       7
+#define STV090x_WIDTH_Px_DC_FROZEN_FIELD       1
+#define STV090x_OFFST_Px_DC_CORRECT_FIELD      6
+#define STV090x_WIDTH_Px_DC_CORRECT_FIELD      1
+#define STV090x_OFFST_Px_AMM_FROZEN_FIELD      5
+#define STV090x_WIDTH_Px_AMM_FROZEN_FIELD      1
+#define STV090x_OFFST_Px_AMM_CORRECT_FIELD     4
+#define STV090x_WIDTH_Px_AMM_CORRECT_FIELD     1
+#define STV090x_OFFST_Px_QUAD_FROZEN_FIELD     3
+#define STV090x_WIDTH_Px_QUAD_FROZEN_FIELD     1
+#define STV090x_OFFST_Px_QUAD_CORRECT_FIELD    2
+#define STV090x_WIDTH_Px_QUAD_CORRECT_FIELD    1
+
+#define STV090x_Px_AGC1CN(__x)                 (0xF406 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1CN                      STV090x_Px_AGC1CN(1)
+#define STV090x_P2_AGC1CN                      STV090x_Px_AGC1CN(2)
+#define STV090x_WIDTH_Px_AGC1_LOCKED_FIELD     7
+#define STV090x_OFFST_Px_AGC1_LOCKED_FIELD     1
+#define STV090x_OFFST_Px_AGC1_MINPOWER_FIELD   4
+#define STV090x_WIDTH_Px_AGC1_MINPOWER_FIELD   1
+#define STV090x_OFFST_Px_AGCOUT_FAST_FIELD     3
+#define STV090x_WIDTH_Px_AGCOUT_FAST_FIELD     1
+#define STV090x_OFFST_Px_AGCIQ_BETA_FIELD      0
+#define STV090x_WIDTH_Px_AGCIQ_BETA_FIELD      3
+
+#define STV090x_Px_AGC1REF(__x)                        (0xF407 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1REF                     STV090x_Px_AGC1REF(1)
+#define STV090x_P2_AGC1REF                     STV090x_Px_AGC1REF(2)
+#define STV090x_OFFST_Px_AGCIQ_REF_FIELD       0
+#define STV090x_WIDTH_Px_AGCIQ_REF_FIELD       8
+
+#define STV090x_Px_IDCCOMP(__x)                        (0xF408 - (__x - 1) * 0x200)
+#define STV090x_P1_IDCCOMP                     STV090x_Px_IDCCOMP(1)
+#define STV090x_P2_IDCCOMP                     STV090x_Px_IDCCOMP(2)
+#define STV090x_OFFST_Px_IAVERAGE_ADJ_FIELD    0
+#define STV090x_WIDTH_Px_IAVERAGE_ADJ_FIELD    8
+
+#define STV090x_Px_QDCCOMP(__x)                        (0xF409 - (__x - 1) * 0x200)
+#define STV090x_P1_QDCCOMP                     STV090x_Px_QDCCOMP(1)
+#define STV090x_P2_QDCCOMP                     STV090x_Px_QDCCOMP(2)
+#define STV090x_OFFST_Px_QAVERAGE_ADJ_FIELD    0
+#define STV090x_WIDTH_Px_QAVERAGE_ADJ_FIELD    8
+
+#define STV090x_Px_POWERI(__x)                 (0xF40A - (__x - 1) * 0x200)
+#define STV090x_P1_POWERI                      STV090x_Px_POWERI(1)
+#define STV090x_P2_POWERI                      STV090x_Px_POWERI(2)
+#define STV090x_OFFST_Px_POWER_I_FIELD         0
+#define STV090x_WIDTH_Px_POWER_I_FIELD         8
+
+#define STV090x_Px_POWERQ(__x)                 (0xF40B - (__x - 1) * 0x200)
+#define STV090x_P1_POWERQ                      STV090x_Px_POWERQ(1)
+#define STV090x_P2_POWERQ                      STV090x_Px_POWERQ(2)
+#define STV090x_OFFST_Px_POWER_Q_FIELD         0
+#define STV090x_WIDTH_Px_POWER_Q_FIELD         8
+
+#define STV090x_Px_AGC1AMM(__x)                        (0xF40C - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1AMM                     STV090x_Px_AGC1AMM(1)
+#define STV090x_P2_AGC1AMM                     STV090x_Px_AGC1AMM(2)
+#define STV090x_OFFST_Px_AMM_VALUE_FIELD       0
+#define STV090x_WIDTH_Px_AMM_VALUE_FIELD       8
+
+#define STV090x_Px_AGC1QUAD(__x)               (0xF40D - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1QUAD                    STV090x_Px_AGC1QUAD(1)
+#define STV090x_P2_AGC1QUAD                    STV090x_Px_AGC1QUAD(2)
+#define STV090x_OFFST_Px_QUAD_VALUE_FIELD      0
+#define STV090x_WIDTH_Px_QUAD_VALUE_FIELD      8
+
+#define STV090x_Px_AGCIQINy(__x, __y)          (0xF40F - (__x-1) * 0x200 - __y * 0x1)
+#define STV090x_P1_AGCIQIN0                    STV090x_Px_AGCIQINy(1, 0)
+#define STV090x_P1_AGCIQIN1                    STV090x_Px_AGCIQINy(1, 1)
+#define STV090x_P2_AGCIQIN0                    STV090x_Px_AGCIQINy(2, 0)
+#define STV090x_P2_AGCIQIN1                    STV090x_Px_AGCIQINy(2, 1)
+#define STV090x_OFFST_Px_AGCIQ_VALUE_FIELD     0
+#define STV090x_WIDTH_Px_AGCIQ_VALUE_FIELD     8
+
+#define STV090x_Px_DEMOD(__x)                  (0xF410 - (__x - 1) * 0x200)
+#define STV090x_P1_DEMOD                       STV090x_Px_DEMOD(1)
+#define STV090x_P2_DEMOD                       STV090x_Px_DEMOD(2)
+#define STV090x_OFFST_Px_MANUAL_S2ROLLOFF_FIELD        7
+#define STV090x_WIDTH_Px_MANUAL_S2ROLLOFF_FIELD        1
+#define STV090x_OFFST_Px_DEMOD_STOP_FIELD      6
+#define STV090x_WIDTH_Px_DEMOD_STOP_FIELD      1
+#define STV090x_OFFST_Px_SPECINV_CONTROL_FIELD 4
+#define STV090x_WIDTH_Px_SPECINV_CONTROL_FIELD 2
+#define STV090x_OFFST_Px_FORCE_ENASAMP_FIELD   3
+#define STV090x_WIDTH_Px_FORCE_ENASAMP_FIELD   1
+#define STV090x_OFFST_Px_MANUAL_SXROLLOFF_FIELD        2
+#define STV090x_WIDTH_Px_MANUAL_SXROLLOFF_FIELD        1
+#define STV090x_OFFST_Px_ROLLOFF_CONTROL_FIELD 0
+#define STV090x_WIDTH_Px_ROLLOFF_CONTROL_FIELD 2
+
+#define STV090x_Px_DMDMODCOD(__x)              (0xF411 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDMODCOD                   STV090x_Px_DMDMODCOD(1)
+#define STV090x_P2_DMDMODCOD                   STV090x_Px_DMDMODCOD(2)
+#define STV090x_OFFST_Px_MANUAL_MODCOD_FIELD   7
+#define STV090x_WIDTH_Px_MANUAL_MODCOD_FIELD   1
+#define STV090x_OFFST_Px_DEMOD_MODCOD_FIELD    2
+#define STV090x_WIDTH_Px_DEMOD_MODCOD_FIELD    5
+#define STV090x_OFFST_Px_DEMOD_TYPE_FIELD      0
+#define STV090x_WIDTH_Px_DEMOD_TYPE_FIELD      2
+
+#define STV090x_Px_DSTATUS(__x)                        (0xF412 - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS                     STV090x_Px_DSTATUS(1)
+#define STV090x_P2_DSTATUS                     STV090x_Px_DSTATUS(2)
+#define STV090x_OFFST_Px_CAR_LOCK_FIELD                7
+#define STV090x_WIDTH_Px_CAR_LOCK_FIELD                1
+#define STV090x_OFFST_Px_TMGLOCK_QUALITY_FIELD 5
+#define STV090x_WIDTH_Px_TMGLOCK_QUALITY_FIELD 2
+#define STV090x_OFFST_Px_LOCK_DEFINITIF_FIELD  3
+#define STV090x_WIDTH_Px_LOCK_DEFINITIF_FIELD  1
+
+#define STV090x_Px_DSTATUS2(__x)               (0xF413 - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS2                    STV090x_Px_DSTATUS2(1)
+#define STV090x_P2_DSTATUS2                    STV090x_Px_DSTATUS2(2)
+#define STV090x_OFFST_Px_DEMOD_DELOCK_FIELD    7
+#define STV090x_WIDTH_Px_DEMOD_DELOCK_FIELD    1
+#define STV090x_OFFST_Px_AGC1_NOSIGNALACK_FIELD        3
+#define STV090x_WIDTH_Px_AGC1_NOSIGNALACK_FIELD        1
+#define STV090x_OFFST_Px_AGC2_OVERFLOW_FIELD   2
+#define STV090x_WIDTH_Px_AGC2_OVERFLOW_FIELD   1
+#define STV090x_OFFST_Px_CFR_OVERFLOW_FIELD    1
+#define STV090x_WIDTH_Px_CFR_OVERFLOW_FIELD    1
+#define STV090x_OFFST_Px_GAMMA_OVERUNDER_FIELD 0
+#define STV090x_WIDTH_Px_GAMMA_OVERUNDER_FIELD 1
+
+#define STV090x_Px_DMDCFGMD(__x)               (0xF414 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFGMD                    STV090x_Px_DMDCFGMD(1)
+#define STV090x_P2_DMDCFGMD                    STV090x_Px_DMDCFGMD(2)
+#define STV090x_OFFST_Px_DVBS2_ENABLE_FIELD    7
+#define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD    1
+#define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD    6
+#define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD    1
+#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD    5 /* check */
+#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD    1
+#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD     4 /* check */
+#define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD     1
+#define STV090x_OFFST_Px_TUN_AUTOSCAN_FIELD    3
+#define STV090x_WIDTH_Px_TUN_AUTOSCAN_FIELD    1
+#define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD  2
+#define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD  1
+#define STV090x_OFFST_Px_TUN_RNG_FIELD         0
+#define STV090x_WIDTH_Px_TUN_RNG_FIELD         2
+
+#define STV090x_Px_DMDCFG2(__x)                        (0xF415 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG2                     STV090x_Px_DMDCFG2(1)
+#define STV090x_P2_DMDCFG2                     STV090x_Px_DMDCFG2(2)
+#define STV090x_OFFST_Px_S1S2_SEQUENTIAL_FIELD 6
+#define STV090x_WIDTH_Px_S1S2_SEQUENTIAL_FIELD 1
+
+#define STV090x_Px_DMDISTATE(__x)              (0xF416 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDISTATE                   STV090x_Px_DMDISTATE(1)
+#define STV090x_P2_DMDISTATE                   STV090x_Px_DMDISTATE(2)
+#define STV090x_OFFST_Px_I2C_DEMOD_MODE_FIELD  0
+#define STV090x_WIDTH_Px_I2C_DEMOD_MODE_FIELD  5
+
+#define STV090x_Px_DMDTOM(__x)                 (0xF417 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_DMDTOM                      STV090x_Px_DMDTOM(1)
+#define STV090x_P2_DMDTOM                      STV090x_Px_DMDTOM(2)
+
+#define STV090x_Px_DMDSTATE(__x)               (0xF41B - (__x - 1) * 0x200)
+#define STV090x_P1_DMDSTATE                    STV090x_Px_DMDSTATE(1)
+#define STV090x_P2_DMDSTATE                    STV090x_Px_DMDSTATE(2)
+#define STV090x_OFFST_Px_HEADER_MODE_FIELD     5
+#define STV090x_WIDTH_Px_HEADER_MODE_FIELD     2
+
+#define STV090x_Px_DMDFLYW(__x)                        (0xF41C - (__x - 1) * 0x200)
+#define STV090x_P1_DMDFLYW                     STV090x_Px_DMDFLYW(1)
+#define STV090x_P2_DMDFLYW                     STV090x_Px_DMDFLYW(2)
+#define STV090x_OFFST_Px_I2C_IRQVAL_FIELD      4
+#define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD      4
+#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD    0 /* check */
+#define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD    4
+
+#define STV090x_Px_DSTATUS3(__x)               (0xF41D - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS3                    STV090x_Px_DSTATUS3(1)
+#define STV090x_P2_DSTATUS3                    STV090x_Px_DSTATUS3(2)
+#define STV090x_OFFST_Px_DEMOD_CFGMODE_FIELD   5
+#define STV090x_WIDTH_Px_DEMOD_CFGMODE_FIELD   2
+
+#define STV090x_Px_DMDCFG3(__x)                        (0xF41E - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG3                     STV090x_Px_DMDCFG3(1)
+#define STV090x_P2_DMDCFG3                     STV090x_Px_DMDCFG3(2)
+#define STV090x_OFFST_Px_NOSTOP_FIFOFULL_FIELD 3
+#define STV090x_WIDTH_Px_NOSTOP_FIFOFULL_FIELD 1
+
+#define STV090x_Px_DMDCFG4(__x)                        (0xf41f - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG4                     STV090x_Px_DMDCFG4(1)
+#define STV090x_P2_DMDCFG4                     STV090x_Px_DMDCFG4(2)
+
+#define STV090x_Px_CORRELMANT(__x)             (0xF420 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELMANT                  STV090x_Px_CORRELMANT(1)
+#define STV090x_P2_CORRELMANT                  STV090x_Px_CORRELMANT(2)
+#define STV090x_OFFST_Px_CORREL_MANT_FIELD     0
+#define STV090x_WIDTH_Px_CORREL_MANT_FIELD     8
+
+#define STV090x_Px_CORRELABS(__x)              (0xF421 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELABS                   STV090x_Px_CORRELABS(1)
+#define STV090x_P2_CORRELABS                   STV090x_Px_CORRELABS(2)
+#define STV090x_OFFST_Px_CORREL_ABS_FIELD      0
+#define STV090x_WIDTH_Px_CORREL_ABS_FIELD      8
+
+#define STV090x_Px_CORRELEXP(__x)              (0xF422 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELEXP                   STV090x_Px_CORRELEXP(1)
+#define STV090x_P2_CORRELEXP                   STV090x_Px_CORRELEXP(2)
+#define STV090x_OFFST_Px_CORREL_ABSEXP_FIELD   4
+#define STV090x_WIDTH_Px_CORREL_ABSEXP_FIELD   4
+#define STV090x_OFFST_Px_CORREL_EXP_FIELD      0
+#define STV090x_WIDTH_Px_CORREL_EXP_FIELD      4
+
+#define STV090x_Px_PLHMODCOD(__x)              (0xF424 - (__x - 1) * 0x200)
+#define STV090x_P1_PLHMODCOD                   STV090x_Px_PLHMODCOD(1)
+#define STV090x_P2_PLHMODCOD                   STV090x_Px_PLHMODCOD(2)
+#define STV090x_OFFST_Px_SPECINV_DEMOD_FIELD   7
+#define STV090x_WIDTH_Px_SPECINV_DEMOD_FIELD   1
+#define STV090x_OFFST_Px_PLH_MODCOD_FIELD      2
+#define STV090x_WIDTH_Px_PLH_MODCOD_FIELD      5
+#define STV090x_OFFST_Px_PLH_TYPE_FIELD                0
+#define STV090x_WIDTH_Px_PLH_TYPE_FIELD                2
+
+#define STV090x_Px_AGCK32(__x)                 (0xf42b - (__x - 1) * 0x200)
+#define STV090x_P1_AGCK32                      STV090x_Px_AGCK32(1)
+#define STV090x_P2_AGCK32                      STV090x_Px_AGCK32(2)
+
+#define STV090x_Px_AGC2O(__x)                  (0xF42C - (__x - 1) * 0x200)
+#define STV090x_P1_AGC2O                       STV090x_Px_AGC2O(1)
+#define STV090x_P2_AGC2O                       STV090x_Px_AGC2O(2)
+
+#define STV090x_Px_AGC2REF(__x)                        (0xF42D - (__x - 1) * 0x200)
+#define STV090x_P1_AGC2REF                     STV090x_Px_AGC2REF(1)
+#define STV090x_P2_AGC2REF                     STV090x_Px_AGC2REF(2)
+#define STV090x_OFFST_Px_AGC2_REF_FIELD                0
+#define STV090x_WIDTH_Px_AGC2_REF_FIELD                8
+
+#define STV090x_Px_AGC1ADJ(__x)                        (0xF42E - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1ADJ                     STV090x_Px_AGC1ADJ(1)
+#define STV090x_P2_AGC1ADJ                     STV090x_Px_AGC1ADJ(2)
+#define STV090x_OFFST_Px_AGC1_ADJUSTED_FIELD   0
+#define STV090x_WIDTH_Px_AGC1_ADJUSTED_FIELD   7
+
+#define STV090x_Px_AGC2Iy(__x, __y)            (0xF437 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_AGC2I0                      STV090x_Px_AGC2Iy(1, 0)
+#define STV090x_P1_AGC2I1                      STV090x_Px_AGC2Iy(1, 1)
+#define STV090x_P2_AGC2I0                      STV090x_Px_AGC2Iy(2, 0)
+#define STV090x_P2_AGC2I1                      STV090x_Px_AGC2Iy(2, 1)
+#define STV090x_OFFST_Px_AGC2_INTEGRATOR_FIELD 0
+#define STV090x_WIDTH_Px_AGC2_INTEGRATOR_FIELD 8
+
+#define STV090x_Px_CARCFG(__x)                 (0xF438 - (__x - 1) * 0x200)
+#define STV090x_P1_CARCFG                      STV090x_Px_CARCFG(1)
+#define STV090x_P2_CARCFG                      STV090x_Px_CARCFG(2)
+#define STV090x_OFFST_Px_EN_CAR2CENTER_FIELD   5
+#define STV090x_WIDTH_Px_EN_CAR2CENTER_FIELD   1
+#define STV090x_OFFST_Px_ROTATON_FIELD         2
+#define STV090x_WIDTH_Px_ROTATON_FIELD         1
+#define STV090x_OFFST_Px_PH_DET_ALGO_FIELD     0
+#define STV090x_WIDTH_Px_PH_DET_ALGO_FIELD     2
+
+#define STV090x_Px_ACLC(__x)                   (0xF439 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC                                STV090x_Px_ACLC(1)
+#define STV090x_P2_ACLC                                STV090x_Px_ACLC(2)
+#define STV090x_OFFST_Px_CAR_ALPHA_MANT_FIELD  4
+#define STV090x_WIDTH_Px_CAR_ALPHA_MANT_FIELD  2
+#define STV090x_OFFST_Px_CAR_ALPHA_EXP_FIELD   0
+#define STV090x_WIDTH_Px_CAR_ALPHA_EXP_FIELD   4
+
+#define STV090x_Px_BCLC(__x)                   (0xF43A - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC                                STV090x_Px_BCLC(1)
+#define STV090x_P2_BCLC                                STV090x_Px_BCLC(2)
+#define STV090x_OFFST_Px_CAR_BETA_MANT_FIELD   4
+#define STV090x_WIDTH_Px_CAR_BETA_MANT_FIELD   2
+#define STV090x_OFFST_Px_CAR_BETA_EXP_FIELD    0
+#define STV090x_WIDTH_Px_CAR_BETA_EXP_FIELD    4
+
+#define STV090x_Px_CARFREQ(__x)                        (0xF43D - (__x - 1) * 0x200)
+#define STV090x_P1_CARFREQ                     STV090x_Px_CARFREQ(1)
+#define STV090x_P2_CARFREQ                     STV090x_Px_CARFREQ(2)
+#define STV090x_OFFST_Px_KC_COARSE_EXP_FIELD   4
+#define STV090x_WIDTH_Px_KC_COARSE_EXP_FIELD   4
+#define STV090x_OFFST_Px_BETA_FREQ_FIELD       0
+#define STV090x_WIDTH_Px_BETA_FREQ_FIELD       4
+
+#define STV090x_Px_CARHDR(__x)                 (0xF43E - (__x - 1) * 0x200)
+#define STV090x_P1_CARHDR                      STV090x_Px_CARHDR(1)
+#define STV090x_P2_CARHDR                      STV090x_Px_CARHDR(2)
+#define STV090x_OFFST_Px_FREQ_HDR_FIELD                0
+#define STV090x_WIDTH_Px_FREQ_HDR_FIELD                8
+
+#define STV090x_Px_LDT(__x)                    (0xF43F - (__x - 1) * 0x200)
+#define STV090x_P1_LDT                         STV090x_Px_LDT(1)
+#define STV090x_P2_LDT                         STV090x_Px_LDT(2)
+#define STV090x_OFFST_Px_CARLOCK_THRES_FIELD   0
+#define STV090x_WIDTH_Px_CARLOCK_THRES_FIELD   8
+
+#define STV090x_Px_LDT2(__x)                   (0xF440 - (__x - 1) * 0x200)
+#define STV090x_P1_LDT2                                STV090x_Px_LDT2(1)
+#define STV090x_P2_LDT2                                STV090x_Px_LDT2(2)
+#define STV090x_OFFST_Px_CARLOCK_THRES2_FIELD  0
+#define STV090x_WIDTH_Px_CARLOCK_THRES2_FIELD  8
+
+#define STV090x_Px_CFRICFG(__x)                        (0xF441 - (__x - 1) * 0x200)
+#define STV090x_P1_CFRICFG                     STV090x_Px_CFRICFG(1)
+#define STV090x_P2_CFRICFG                     STV090x_Px_CFRICFG(2)
+#define STV090x_OFFST_Px_NEG_CFRSTEP_FIELD     0
+#define STV090x_WIDTH_Px_NEG_CFRSTEP_FIELD     1
+
+#define STV090x_Pn_CFRUPy(__x, __y)            (0xF443 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRUP0                      STV090x_Pn_CFRUPy(1, 0)
+#define STV090x_P1_CFRUP1                      STV090x_Pn_CFRUPy(1, 1)
+#define STV090x_P2_CFRUP0                      STV090x_Pn_CFRUPy(2, 0)
+#define STV090x_P2_CFRUP1                      STV090x_Pn_CFRUPy(2, 1)
+#define STV090x_OFFST_Px_CFR_UP_FIELD          0
+#define STV090x_WIDTH_Px_CFR_UP_FIELD          8
+
+#define STV090x_Pn_CFRLOWy(__x, __y)           (0xF447 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRLOW0                     STV090x_Pn_CFRLOWy(1, 0)
+#define STV090x_P1_CFRLOW1                     STV090x_Pn_CFRLOWy(1, 1)
+#define STV090x_P2_CFRLOW0                     STV090x_Pn_CFRLOWy(2, 0)
+#define STV090x_P2_CFRLOW1                     STV090x_Pn_CFRLOWy(2, 1)
+#define STV090x_OFFST_Px_CFR_LOW_FIELD         0
+#define STV090x_WIDTH_Px_CFR_LOW_FIELD         8
+
+#define STV090x_Pn_CFRINITy(__x, __y)          (0xF449 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRINIT0                    STV090x_Pn_CFRINITy(1, 0)
+#define STV090x_P1_CFRINIT1                    STV090x_Pn_CFRINITy(1, 1)
+#define STV090x_P2_CFRINIT0                    STV090x_Pn_CFRINITy(2, 0)
+#define STV090x_P2_CFRINIT1                    STV090x_Pn_CFRINITy(2, 1)
+#define STV090x_OFFST_Px_CFR_INIT_FIELD                0
+#define STV090x_WIDTH_Px_CFR_INIT_FIELD                8
+
+#define STV090x_Px_CFRINC1(__x)                        (0xF44A - (__x - 1) * 0x200)
+#define STV090x_P1_CFRINC1                     STV090x_Px_CFRINC1(1)
+#define STV090x_P2_CFRINC1                     STV090x_Px_CFRINC1(2)
+#define STV090x_OFFST_Px_CFR_INC1_FIELD                0
+#define STV090x_WIDTH_Px_CFR_INC1_FIELD                7
+
+#define STV090x_Px_CFRINC0(__x)                        (0xF44B - (__x - 1) * 0x200)
+#define STV090x_P1_CFRINC0                     STV090x_Px_CFRINC0(1)
+#define STV090x_P2_CFRINC0                     STV090x_Px_CFRINC0(2)
+#define STV090x_OFFST_Px_CFR_INC0_FIELD                4
+#define STV090x_WIDTH_Px_CFR_INC0_FIELD                4
+
+#define STV090x_Pn_CFRy(__x, __y)              (0xF44E - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFR0                                STV090x_Pn_CFRy(1, 0)
+#define STV090x_P1_CFR1                                STV090x_Pn_CFRy(1, 1)
+#define STV090x_P1_CFR2                                STV090x_Pn_CFRy(1, 2)
+#define STV090x_P2_CFR0                                STV090x_Pn_CFRy(2, 0)
+#define STV090x_P2_CFR1                                STV090x_Pn_CFRy(2, 1)
+#define STV090x_P2_CFR2                                STV090x_Pn_CFRy(2, 2)
+#define STV090x_OFFST_Px_CAR_FREQ_FIELD                0
+#define STV090x_WIDTH_Px_CAR_FREQ_FIELD                8
+
+#define STV090x_Px_LDI(__x)                    (0xF44F - (__x - 1) * 0x200)
+#define STV090x_P1_LDI                         STV090x_Px_LDI(1)
+#define STV090x_P2_LDI                         STV090x_Px_LDI(2)
+#define STV090x_OFFST_Px_LOCK_DET_INTEGR_FIELD 0
+#define STV090x_WIDTH_Px_LOCK_DET_INTEGR_FIELD 8
+
+#define STV090x_Px_TMGCFG(__x)                 (0xF450 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGCFG                      STV090x_Px_TMGCFG(1)
+#define STV090x_P2_TMGCFG                      STV090x_Px_TMGCFG(2)
+#define STV090x_OFFST_Px_TMGLOCK_BETA_FIELD    6
+#define STV090x_WIDTH_Px_TMGLOCK_BETA_FIELD    2
+#define STV090x_OFFST_Px_DO_TIMING_FIELD       4
+#define STV090x_WIDTH_Px_DO_TIMING_FIELD       1
+#define STV090x_OFFST_Px_TMG_MINFREQ_FIELD     0
+#define STV090x_WIDTH_Px_TMG_MINFREQ_FIELD     2
+
+#define STV090x_Px_RTC(__x)                    (0xF451 - (__x - 1) * 0x200)
+#define STV090x_P1_RTC                         STV090x_Px_RTC(1)
+#define STV090x_P2_RTC                         STV090x_Px_RTC(2)
+#define STV090x_OFFST_Px_TMGALPHA_EXP_FIELD    4
+#define STV090x_WIDTH_Px_TMGALPHA_EXP_FIELD    4
+#define STV090x_OFFST_Px_TMGBETA_EXP_FIELD     0
+#define STV090x_WIDTH_Px_TMGBETA_EXP_FIELD     4
+
+#define STV090x_Px_RTCS2(__x)                  (0xF452 - (__x - 1) * 0x200)
+#define STV090x_P1_RTCS2                       STV090x_Px_RTCS2(1)
+#define STV090x_P2_RTCS2                       STV090x_Px_RTCS2(2)
+#define STV090x_OFFST_Px_TMGALPHAS2_EXP_FIELD  4
+#define STV090x_WIDTH_Px_TMGALPHAS2_EXP_FIELD  4
+#define STV090x_OFFST_Px_TMGBETAS2_EXP_FIELD   0
+#define STV090x_WIDTH_Px_TMGBETAS2_EXP_FIELD   4
+
+#define STV090x_Px_TMGTHRISE(__x)              (0xF453 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGTHRISE                   STV090x_Px_TMGTHRISE(1)
+#define STV090x_P2_TMGTHRISE                   STV090x_Px_TMGTHRISE(2)
+#define STV090x_OFFST_Px_TMGLOCK_THRISE_FIELD  0
+#define STV090x_WIDTH_Px_TMGLOCK_THRISE_FIELD  8
+
+#define STV090x_Px_TMGTHFALL(__x)              (0xF454 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGTHFALL                   STV090x_Px_TMGTHFALL(1)
+#define STV090x_P2_TMGTHFALL                   STV090x_Px_TMGTHFALL(2)
+#define STV090x_OFFST_Px_TMGLOCK_THFALL_FIELD  0
+#define STV090x_WIDTH_Px_TMGLOCK_THFALL_FIELD  8
+
+#define STV090x_Px_SFRUPRATIO(__x)             (0xF455 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUPRATIO                  STV090x_Px_SFRUPRATIO(1)
+#define STV090x_P2_SFRUPRATIO                  STV090x_Px_SFRUPRATIO(2)
+#define STV090x_OFFST_Px_SFR_UPRATIO_FIELD     0
+#define STV090x_WIDTH_Px_SFR_UPRATIO_FIELD     8
+
+#define STV090x_Px_SFRLOWRATIO(__x)            (0xF456 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOWRATIO                 STV090x_Px_SFRLOWRATIO(1)
+#define STV090x_P2_SFRLOWRATIO                 STV090x_Px_SFRLOWRATIO(2)
+#define STV090x_OFFST_Px_SFR_LOWRATIO_FIELD    0
+#define STV090x_WIDTH_Px_SFR_LOWRATIO_FIELD    8
+
+#define STV090x_Px_KREFTMG(__x)                        (0xF458 - (__x - 1) * 0x200)
+#define STV090x_P1_KREFTMG                     STV090x_Px_KREFTMG(1)
+#define STV090x_P2_KREFTMG                     STV090x_Px_KREFTMG(2)
+#define STV090x_OFFST_Px_KREF_TMG_FIELD                0
+#define STV090x_WIDTH_Px_KREF_TMG_FIELD                8
+
+#define STV090x_Px_SFRSTEP(__x)                        (0xF459 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRSTEP                     STV090x_Px_SFRSTEP(1)
+#define STV090x_P2_SFRSTEP                     STV090x_Px_SFRSTEP(2)
+#define STV090x_OFFST_Px_SFR_SCANSTEP_FIELD    4
+#define STV090x_WIDTH_Px_SFR_SCANSTEP_FIELD    4
+#define STV090x_OFFST_Px_SFR_CENTERSTEP_FIELD  0
+#define STV090x_WIDTH_Px_SFR_CENTERSTEP_FIELD  4
+
+#define STV090x_Px_TMGCFG2(__x)                        (0xF45A - (__x - 1) * 0x200)
+#define STV090x_P1_TMGCFG2                     STV090x_Px_TMGCFG2(1)
+#define STV090x_P2_TMGCFG2                     STV090x_Px_TMGCFG2(2)
+#define STV090x_OFFST_Px_SFRRATIO_FINE_FIELD   0
+#define STV090x_WIDTH_Px_SFRRATIO_FINE_FIELD   1
+
+#define STV090x_Px_SFRINIT1(__x)               (0xF45E - (__x - 1) * 0x200)
+#define STV090x_P1_SFRINIT1                    STV090x_Px_SFRINIT1(1)
+#define STV090x_P2_SFRINIT1                    STV090x_Px_SFRINIT1(2)
+#define STV090x_OFFST_Px_SFR_INIT_FIELD                0
+#define STV090x_WIDTH_Px_SFR_INIT_FIELD                8
+
+#define STV090x_Px_SFRINIT0(__x)               (0xF45F - (__x - 1) * 0x200)
+#define STV090x_P1_SFRINIT0                    STV090x_Px_SFRINIT0(1)
+#define STV090x_P2_SFRINIT0                    STV090x_Px_SFRINIT0(2)
+#define STV090x_OFFST_Px_SFR_INIT_FIELD                0
+#define STV090x_WIDTH_Px_SFR_INIT_FIELD                8
+
+#define STV090x_Px_SFRUP1(__x)                 (0xF460 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUP1                      STV090x_Px_SFRUP1(1)
+#define STV090x_P2_SFRUP1                      STV090x_Px_SFRUP1(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_UP1_FIELD   0
+#define STV090x_WIDTH_Px_SYMB_FREQ_UP1_FIELD   7
+
+#define STV090x_Px_SFRUP0(__x)                 (0xF461 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUP0                      STV090x_Px_SFRUP0(1)
+#define STV090x_P2_SFRUP0                      STV090x_Px_SFRUP0(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_UP0_FIELD   0
+#define STV090x_WIDTH_Px_SYMB_FREQ_UP0_FIELD   8
+
+#define STV090x_Px_SFRLOW1(__x)                        (0xF462 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOW1                     STV090x_Px_SFRLOW1(1)
+#define STV090x_P2_SFRLOW1                     STV090x_Px_SFRLOW1(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_LOW1_FIELD  0
+#define STV090x_WIDTH_Px_SYMB_FREQ_LOW1_FIELD  7
+
+#define STV090x_Px_SFRLOW0(__x)                        (0xF463 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOW0                     STV090x_Px_SFRLOW0(1)
+#define STV090x_P2_SFRLOW0                     STV090x_Px_SFRLOW0(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD  0
+#define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD  8
+
+#define STV090x_Px_SFRy(__x, __y)              (0xF464 - (__x-1) * 0x200 + (3 - __y))
+#define STV090x_P1_SFR0                                STV090x_Px_SFRy(1, 0)
+#define STV090x_P1_SFR1                                STV090x_Px_SFRy(1, 1)
+#define STV090x_P1_SFR2                                STV090x_Px_SFRy(1, 2)
+#define STV090x_P1_SFR3                                STV090x_Px_SFRy(1, 3)
+#define STV090x_P2_SFR0                                STV090x_Px_SFRy(2, 0)
+#define STV090x_P2_SFR1                                STV090x_Px_SFRy(2, 1)
+#define STV090x_P2_SFR2                                STV090x_Px_SFRy(2, 2)
+#define STV090x_P2_SFR3                                STV090x_Px_SFRy(2, 3)
+#define STV090x_OFFST_Px_SYMB_FREQ_FIELD       0
+#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD       32
+
+#define STV090x_Px_TMGREG2(__x)                        (0xF468 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG2                     STV090x_Px_TMGREG2(1)
+#define STV090x_P2_TMGREG2                     STV090x_Px_TMGREG2(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD          0
+#define STV090x_WIDTH_Px_TMGREG_FIELD          8
+
+#define STV090x_Px_TMGREG1(__x)                        (0xF469 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG1                     STV090x_Px_TMGREG1(1)
+#define STV090x_P2_TMGREG1                             STV090x_Px_TMGREG1(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD          0
+#define STV090x_WIDTH_Px_TMGREG_FIELD          8
+
+#define STV090x_Px_TMGREG0(__x)                        (0xF46A - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG0                     STV090x_Px_TMGREG0(1)
+#define STV090x_P2_TMGREG0                     STV090x_Px_TMGREG0(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD          0
+#define STV090x_WIDTH_Px_TMGREG_FIELD          8
+
+#define STV090x_Px_TMGLOCKy(__x, __y)          (0xF46C - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_TMGLOCK0                    STV090x_Px_TMGLOCKy(1, 0)
+#define STV090x_P1_TMGLOCK1                    STV090x_Px_TMGLOCKy(1, 1)
+#define STV090x_P2_TMGLOCK0                    STV090x_Px_TMGLOCKy(2, 0)
+#define STV090x_P2_TMGLOCK1                    STV090x_Px_TMGLOCKy(2, 1)
+#define STV090x_OFFST_Px_TMGLOCK_LEVEL_FIELD   0
+#define STV090x_WIDTH_Px_TMGLOCK_LEVEL_FIELD   8
+
+#define STV090x_Px_TMGOBS(__x)                 (0xF46D - (__x - 1) * 0x200)
+#define STV090x_P1_TMGOBS                      STV090x_Px_TMGOBS(1)
+#define STV090x_P2_TMGOBS                      STV090x_Px_TMGOBS(2)
+#define STV090x_OFFST_Px_ROLLOFF_STATUS_FIELD  6
+#define STV090x_WIDTH_Px_ROLLOFF_STATUS_FIELD  2
+
+#define STV090x_Px_EQUALCFG(__x)               (0xF46F - (__x - 1) * 0x200)
+#define STV090x_P1_EQUALCFG                    STV090x_Px_EQUALCFG(1)
+#define STV090x_P2_EQUALCFG                    STV090x_Px_EQUALCFG(2)
+#define STV090x_OFFST_Px_EQUAL_ON_FIELD                6
+#define STV090x_WIDTH_Px_EQUAL_ON_FIELD                1
+#define STV090x_OFFST_Px_MU_EQUALDFE_FIELD     0
+#define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD     3
+
+#define STV090x_Px_EQUAIy(__x, __y)            (0xf470 - (__x - 1) * 0x200 + (__y - 1))
+#define STV090x_P1_EQUAI1                      STV090x_Px_EQUAIy(1, 1)
+#define STV090x_P1_EQUAI2                      STV090x_Px_EQUAIy(1, 2)
+#define STV090x_P1_EQUAI3                      STV090x_Px_EQUAIy(1, 3)
+#define STV090x_P1_EQUAI4                      STV090x_Px_EQUAIy(1, 4)
+#define STV090x_P1_EQUAI5                      STV090x_Px_EQUAIy(1, 5)
+#define STV090x_P1_EQUAI6                      STV090x_Px_EQUAIy(1, 6)
+#define STV090x_P1_EQUAI7                      STV090x_Px_EQUAIy(1, 7)
+#define STV090x_P1_EQUAI8                      STV090x_Px_EQUAIy(1, 8)
+
+#define STV090x_P2_EQUAI1                      STV090x_Px_EQUAIy(2, 1)
+#define STV090x_P2_EQUAI2                      STV090x_Px_EQUAIy(2, 2)
+#define STV090x_P2_EQUAI3                      STV090x_Px_EQUAIy(2, 3)
+#define STV090x_P2_EQUAI4                      STV090x_Px_EQUAIy(2, 4)
+#define STV090x_P2_EQUAI5                      STV090x_Px_EQUAIy(2, 5)
+#define STV090x_P2_EQUAI6                      STV090x_Px_EQUAIy(2, 6)
+#define STV090x_P2_EQUAI7                      STV090x_Px_EQUAIy(2, 7)
+#define STV090x_P2_EQUAI8                      STV090x_Px_EQUAIy(2, 8)
+#define STV090x_OFFST_Px_EQUA_ACCIy_FIELD      0
+#define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD      8
+
+#define STV090x_Px_EQUAQy(__x, __y)            (0xf471 - (__x - 1) * 0x200 + (__y - 1))
+#define STV090x_P1_EQUAQ1                      STV090x_Px_EQUAQy(1, 1)
+#define STV090x_P1_EQUAQ2                      STV090x_Px_EQUAQy(1, 2)
+#define STV090x_P1_EQUAQ3                      STV090x_Px_EQUAQy(1, 3)
+#define STV090x_P1_EQUAQ4                      STV090x_Px_EQUAQy(1, 4)
+#define STV090x_P1_EQUAQ5                      STV090x_Px_EQUAQy(1, 5)
+#define STV090x_P1_EQUAQ6                      STV090x_Px_EQUAQy(1, 6)
+#define STV090x_P1_EQUAQ7                      STV090x_Px_EQUAQy(1, 7)
+#define STV090x_P1_EQUAQ8                      STV090x_Px_EQUAQy(1, 8)
+
+#define STV090x_P2_EQUAQ1                      STV090x_Px_EQUAQy(2, 1)
+#define STV090x_P2_EQUAQ2                      STV090x_Px_EQUAQy(2, 2)
+#define STV090x_P2_EQUAQ3                      STV090x_Px_EQUAQy(2, 3)
+#define STV090x_P2_EQUAQ4                      STV090x_Px_EQUAQy(2, 4)
+#define STV090x_P2_EQUAQ5                      STV090x_Px_EQUAQy(2, 5)
+#define STV090x_P2_EQUAQ6                      STV090x_Px_EQUAQy(2, 6)
+#define STV090x_P2_EQUAQ7                      STV090x_Px_EQUAQy(2, 7)
+#define STV090x_P2_EQUAQ8                      STV090x_Px_EQUAQy(2, 8)
+#define STV090x_OFFST_Px_EQUA_ACCQy_FIELD      0
+#define STV090x_WIDTH_Px_EQUA_ACCQy_FIELD      8
+
+#define STV090x_Px_NNOSDATATy(__x, __y)                (0xf481 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSDATAT0                  STV090x_Px_NNOSDATATy(1, 0)
+#define STV090x_P1_NNOSDATAT1                  STV090x_Px_NNOSDATATy(1, 1)
+#define STV090x_P2_NNOSDATAT0                  STV090x_Px_NNOSDATATy(2, 0)
+#define STV090x_P2_NNOSDATAT1                  STV090x_Px_NNOSDATATy(2, 1)
+#define STV090x_OFFST_Px_NOSDATAT_NORMED_FIELD 0
+#define STV090x_WIDTH_Px_NOSDATAT_NORMED_FIELD 8
+
+#define STV090x_Px_NNOSDATAy(__x, __y)         (0xf483 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSDATA0                   STV090x_Px_NNOSDATAy(1, 0)
+#define STV090x_P1_NNOSDATA1                   STV090x_Px_NNOSDATAy(1, 1)
+#define STV090x_P2_NNOSDATA0                   STV090x_Px_NNOSDATAy(2, 0)
+#define STV090x_P2_NNOSDATA1                   STV090x_Px_NNOSDATAy(2, 1)
+#define STV090x_OFFST_Px_NOSDATA_NORMED_FIELD  0
+#define STV090x_WIDTH_Px_NOSDATA_NORMED_FIELD  8
+
+#define STV090x_Px_NNOSPLHTy(__x, __y)         (0xf485 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSPLHT0                   STV090x_Px_NNOSPLHTy(1, 0)
+#define STV090x_P1_NNOSPLHT1                   STV090x_Px_NNOSPLHTy(1, 1)
+#define STV090x_P2_NNOSPLHT0                   STV090x_Px_NNOSPLHTy(2, 0)
+#define STV090x_P2_NNOSPLHT1                   STV090x_Px_NNOSPLHTy(2, 1)
+#define STV090x_OFFST_Px_NOSPLHT_NORMED_FIELD  0
+#define STV090x_WIDTH_Px_NOSPLHT_NORMED_FIELD  8
+
+#define STV090x_Px_NNOSPLHy(__x, __y)          (0xf487 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSPLH0                    STV090x_Px_NNOSPLHy(1, 0)
+#define STV090x_P1_NNOSPLH1                    STV090x_Px_NNOSPLHy(1, 1)
+#define STV090x_P2_NNOSPLH0                    STV090x_Px_NNOSPLHy(2, 0)
+#define STV090x_P2_NNOSPLH1                    STV090x_Px_NNOSPLHy(2, 1)
+#define STV090x_OFFST_Px_NOSPLH_NORMED_FIELD   0
+#define STV090x_WIDTH_Px_NOSPLH_NORMED_FIELD   8
+
+#define STV090x_Px_NOSDATATy(__x, __y)                 (0xf489 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSDATAT0                           STV090x_Px_NOSDATATy(1, 0)
+#define STV090x_P1_NOSDATAT1                           STV090x_Px_NOSDATATy(1, 1)
+#define STV090x_P2_NOSDATAT0                           STV090x_Px_NOSDATATy(2, 0)
+#define STV090x_P2_NOSDATAT1                           STV090x_Px_NOSDATATy(2, 1)
+#define STV090x_OFFST_Px_NOSDATAT_UNNORMED_FIELD       0
+#define STV090x_WIDTH_Px_NOSDATAT_UNNORMED_FIELD       8
+
+#define STV090x_Px_NOSDATAy(__x, __y)          (0xf48b - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSDATA0                    STV090x_Px_NOSDATAy(1, 0)
+#define STV090x_P1_NOSDATA1                    STV090x_Px_NOSDATAy(1, 1)
+#define STV090x_P2_NOSDATA0                    STV090x_Px_NOSDATAy(2, 0)
+#define STV090x_P2_NOSDATA1                    STV090x_Px_NOSDATAy(2, 1)
+#define STV090x_OFFST_Px_NOSDATA_UNNORMED_FIELD        0
+#define STV090x_WIDTH_Px_NOSDATA_UNNORMED_FIELD        8
+
+#define STV090x_Px_NOSPLHTy(__x, __y)          (0xf48d - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSPLHT0                    STV090x_Px_NOSPLHTy(1, 0)
+#define STV090x_P1_NOSPLHT1                    STV090x_Px_NOSPLHTy(1, 1)
+#define STV090x_P2_NOSPLHT0                    STV090x_Px_NOSPLHTy(2, 0)
+#define STV090x_P2_NOSPLHT1                    STV090x_Px_NOSPLHTy(2, 1)
+#define STV090x_OFFST_Px_NOSPLHT_UNNORMED_FIELD        0
+#define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD        8
+
+#define STV090x_Px_NOSPLHy(__x, __y)           (0xf48f - (__x - 1) * 0x200 - __y * 0x1)
+#define STv090x_P1_NOSPLH0                     STV090x_Px_NOSPLHy(1, 0)
+#define STv090x_P1_NOSPLH1                     STV090x_Px_NOSPLHy(1, 1)
+#define STv090x_P2_NOSPLH0                     STV090x_Px_NOSPLHy(2, 0)
+#define STv090x_P2_NOSPLH1                     STV090x_Px_NOSPLHy(2, 1)
+#define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD 0
+#define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD 8
+
+#define STV090x_Px_CAR2CFG(__x)                        (0xf490 - (__x - 1) * 0x200)
+#define STV090x_P1_CAR2CFG                     STV090x_Px_CAR2CFG(1)
+#define STV090x_P2_CAR2CFG                     STV090x_Px_CAR2CFG(2)
+#define STV090x_OFFST_Px_PN4_SELECT_FIELD      6
+#define STV090x_WIDTH_Px_PN4_SELECT_FIELD      1
+#define STV090x_OFFST_Px_CFR2_STOPDVBS1_FIELD  5
+#define STV090x_WIDTH_Px_CFR2_STOPDVBS1_FIELD  1
+#define STV090x_OFFST_Px_ROTA2ON_FIELD         2
+#define STV090x_WIDTH_Px_ROTA2ON_FIELD         1
+#define STV090x_OFFST_Px_PH_DET_ALGO2_FIELD    0
+#define STV090x_WIDTH_Px_PH_DET_ALGO2_FIELD    2
+
+#define STV090x_Px_ACLC2(__x)                  (0xf491 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2                       STV090x_Px_ACLC2(1)
+#define STV090x_P2_ACLC2                       STV090x_Px_ACLC2(2)
+#define STV090x_OFFST_Px_CAR2_ALPHA_MANT_FIELD 4
+#define STV090x_WIDTH_Px_CAR2_ALPHA_MANT_FIELD 2
+#define STV090x_OFFST_Px_CAR2_ALPHA_EXP_FIELD  0
+#define STV090x_WIDTH_Px_CAR2_ALPHA_EXP_FIELD  4
+
+#define STV090x_Px_BCLC2(__x)                  (0xf492 - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2                       STV090x_Px_BCLC2(1)
+#define STV090x_P2_BCLC2                       STV090x_Px_BCLC2(2)
+#define STV090x_OFFST_Px_CAR2_BETA_MANT_FIELD  4
+#define STV090x_WIDTH_Px_CAR2_BETA_MANT_FIELD  2
+#define STV090x_OFFST_Px_CAR2_BETA_EXP_FIELD   0
+#define STV090x_WIDTH_Px_CAR2_BETA_EXP_FIELD   4
+
+#define STV090x_Px_ACLC2S2Q(__x)               (0xf497 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S2Q                    STV090x_Px_ACLC2S2Q(1)
+#define STV090x_P2_ACLC2S2Q                    STV090x_Px_ACLC2S2Q(2)
+#define STV090x_OFFST_Px_ENAB_SPSKSYMB_FIELD   7
+#define STV090x_WIDTH_Px_ENAB_SPSKSYMB_FIELD   1
+#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_M_FIELD 4
+#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_M_FIELD 2
+#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_E_FIELD 0
+#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_E_FIELD 4
+
+#define STV090x_Px_ACLC2S28(__x)               (0xf498 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S28                    STV090x_Px_ACLC2S28(1)
+#define STV090x_P2_ACLC2S28                    STV090x_Px_ACLC2S28(2)
+#define STV090x_OFFST_Px_CAR2S2_8_ALPH_M_FIELD 4
+#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_M_FIELD 2
+#define STV090x_OFFST_Px_CAR2S2_8_ALPH_E_FIELD 0
+#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_E_FIELD 4
+
+#define STV090x_Px_ACLC2S216A(__x)             (0xf499 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S216A                  STV090x_Px_ACLC2S216A(1)
+#define STV090x_P2_ACLC2S216A                  STV090x_Px_ACLC2S216A(2)
+#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_M_FIELD       4
+#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_M_FIELD       2
+#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD       0
+#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD       4
+
+#define STV090x_Px_ACLC2S232A(__x)             (0xf499 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S232A                  STV090x_Px_ACLC2S232A(1)
+#define STV090x_P2_ACLC2S232A                  STV090x_Px_ACLC2S232A(2)
+#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD       4
+#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_M_FIELD       2
+#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_E_FIELD       0
+#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_E_FIELD       4
+
+#define STV090x_Px_BCLC2S2Q(__x)               (0xf49c - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S2Q                    STV090x_Px_BCLC2S2Q(1)
+#define STV090x_P2_BCLC2S2Q                    STV090x_Px_BCLC2S2Q(2)
+#define STV090x_OFFST_Px_CAR2S2_Q_BETA_M_FIELD 4
+#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_M_FIELD 2
+#define STV090x_OFFST_Px_CAR2S2_Q_BETA_E_FIELD 0
+#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_E_FIELD 4
+
+#define STV090x_Px_BCLC2S28(__x)               (0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S28                    STV090x_Px_BCLC2S28(1)
+#define STV090x_P2_BCLC2S28                    STV090x_Px_BCLC2S28(1)
+#define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD 4
+#define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD 2
+#define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD 0
+#define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD 4
+
+#define STV090x_Px_BCLC2S216A(__x)             (0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S216A                  STV090x_Px_BCLC2S216A(1)
+#define STV090x_P2_BCLC2S216A                  STV090x_Px_BCLC2S216A(1)
+#define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD       4
+#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD       2
+#define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD       0
+#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD       4
+
+#define STV090x_Px_BCLC2S232A(__x)             (0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S232A                  STV090x_Px_BCLC2S232A(1)
+#define STV090x_P2_BCLC2S232A                  STV090x_Px_BCLC2S232A(1)
+#define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD       4
+#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD       2
+#define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD       0
+#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_E_FIELD       4
+
+#define STV090x_Px_PLROOT2(__x)                        (0xf4ac - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT2                     STV090x_Px_PLROOT2(1)
+#define STV090x_P2_PLROOT2                     STV090x_Px_PLROOT2(2)
+#define STV090x_OFFST_Px_PLSCRAMB_MODE_FIELD   2
+#define STV090x_WIDTH_Px_PLSCRAMB_MODE_FIELD   2
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT_FIELD   0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT_FIELD   2
+
+#define STV090x_Px_PLROOT1(__x)                        (0xf4ad - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT1                     STV090x_Px_PLROOT1(1)
+#define STV090x_P2_PLROOT1                     STV090x_Px_PLROOT1(2)
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT1_FIELD  0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT1_FIELD  8
+
+#define STV090x_Px_PLROOT0(__x)                        (0xf4ae - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT0                     STV090x_Px_PLROOT0(1)
+#define STV090x_P2_PLROOT0                     STV090x_Px_PLROOT0(2)
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT0_FIELD  0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT0_FIELD  8
+
+#define STV090x_Px_MODCODLST0(__x)             (0xf4b0 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_MODCODLST0                  STV090x_Px_MODCODLST0(1)
+#define STV090x_P2_MODCODLST0                  STV090x_Px_MODCODLST0(2)
+
+#define STV090x_Px_MODCODLST1(__x)             (0xf4b1 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST1                  STV090x_Px_MODCODLST1(1)
+#define STV090x_P2_MODCODLST1                  STV090x_Px_MODCODLST1(2)
+#define STV090x_OFFST_Px_DIS_MODCOD29_FIELD    4
+#define STV090x_WIDTH_Px_DIS_MODCOD29T_FIELD   4
+#define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD  0
+#define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD  4
+
+#define STV090x_Px_MODCODLST2(__x)             (0xf4b2 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST2                  STV090x_Px_MODCODLST2(1)
+#define STV090x_P2_MODCODLST2                  STV090x_Px_MODCODLST2(2)
+#define STV090x_OFFST_Px_DIS_32PSK_8_9_FIELD   4
+#define STV090x_WIDTH_Px_DIS_32PSK_8_9_FIELD   4
+#define STV090x_OFFST_Px_DIS_32PSK_5_6_FIELD   0
+#define STV090x_WIDTH_Px_DIS_32PSK_5_6_FIELD   4
+
+#define STV090x_Px_MODCODLST3(__x)             (0xf4b3 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST3                  STV090x_Px_MODCODLST3(1)
+#define STV090x_P2_MODCODLST3                  STV090x_Px_MODCODLST3(2)
+#define STV090x_OFFST_Px_DIS_32PSK_4_5_FIELD   4
+#define STV090x_WIDTH_Px_DIS_32PSK_4_5_FIELD   4
+#define STV090x_OFFST_Px_DIS_32PSK_3_4_FIELD   0
+#define STV090x_WIDTH_Px_DIS_32PSK_3_4_FIELD   4
+
+#define STV090x_Px_MODCODLST4(__x)             (0xf4b4 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST4                  STV090x_Px_MODCODLST4(1)
+#define STV090x_P2_MODCODLST4                  STV090x_Px_MODCODLST4(2)
+#define STV090x_OFFST_Px_DIS_16PSK_9_10_FIELD  4
+#define STV090x_WIDTH_Px_DIS_16PSK_9_10_FIELD  4
+#define STV090x_OFFST_Px_DIS_16PSK_8_9_FIELD   0
+#define STV090x_WIDTH_Px_DIS_16PSK_8_9_FIELD   4
+
+#define STV090x_Px_MODCODLST5(__x)             (0xf4b5 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST5                  STV090x_Px_MODCODLST5(1)
+#define STV090x_P2_MODCODLST5                  STV090x_Px_MODCODLST5(2)
+#define STV090x_OFFST_Px_DIS_16PSK_5_6_FIELD   4
+#define STV090x_WIDTH_Px_DIS_16PSK_5_6_FIELD   4
+#define STV090x_OFFST_Px_DIS_16PSK_4_5_FIELD   0
+#define STV090x_WIDTH_Px_DIS_16PSK_4_5_FIELD   4
+
+#define STV090x_Px_MODCODLST6(__x)             (0xf4b6 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST6                  STV090x_Px_MODCODLST6(1)
+#define STV090x_P2_MODCODLST6                  STV090x_Px_MODCODLST6(2)
+#define STV090x_OFFST_Px_DIS_16PSK_3_4_FIELD   4
+#define STV090x_WIDTH_Px_DIS_16PSK_3_4_FIELD   4
+#define STV090x_OFFST_Px_DIS_16PSK_2_3_FIELD   0
+#define STV090x_WIDTH_Px_DIS_16PSK_2_3_FIELD   4
+
+#define STV090x_Px_MODCODLST7(__x)             (0xf4b7 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST7                  STV090x_Px_MODCODLST7(1)
+#define STV090x_P2_MODCODLST7                  STV090x_Px_MODCODLST7(2)
+#define STV090x_OFFST_Px_DIS_8P_9_10_FIELD     4
+#define STV090x_WIDTH_Px_DIS_8P_9_10_FIELD     4
+#define STV090x_OFFST_Px_DIS_8P_8_9_FIELD      0
+#define STV090x_WIDTH_Px_DIS_8P_8_9_FIELD      4
+
+#define STV090x_Px_MODCODLST8(__x)             (0xf4b8 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST8                  STV090x_Px_MODCODLST8(1)
+#define STV090x_P2_MODCODLST8                  STV090x_Px_MODCODLST8(2)
+#define STV090x_OFFST_Px_DIS_8P_5_6_FIELD      4
+#define STV090x_WIDTH_Px_DIS_8P_5_6_FIELD      4
+#define STV090x_OFFST_Px_DIS_8P_3_4_FIELD      0
+#define STV090x_WIDTH_Px_DIS_8P_3_4_FIELD      4
+
+#define STV090x_Px_MODCODLST9(__x)             (0xf4b9 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST9                  STV090x_Px_MODCODLST9(1)
+#define STV090x_P2_MODCODLST9                  STV090x_Px_MODCODLST9(2)
+#define STV090x_OFFST_Px_DIS_8P_2_3_FIELD      4
+#define STV090x_WIDTH_Px_DIS_8P_2_3_FIELD      4
+#define STV090x_OFFST_Px_DIS_8P_3_5_FIELD      0
+#define STV090x_WIDTH_Px_DIS_8P_3_5_FIELD      4
+
+#define STV090x_Px_MODCODLSTA(__x)             (0xf4ba - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTA                  STV090x_Px_MODCODLSTA(1)
+#define STV090x_P2_MODCODLSTA                  STV090x_Px_MODCODLSTA(2)
+#define STV090x_OFFST_Px_DIS_QP_9_10_FIELD     4
+#define STV090x_WIDTH_Px_DIS_QP_9_10_FIELD     4
+#define STV090x_OFFST_Px_DIS_QP_8_9_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_8_9_FIELD      4
+
+#define STV090x_Px_MODCODLSTB(__x)             (0xf4bb - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTB                  STV090x_Px_MODCODLSTB(1)
+#define STV090x_P2_MODCODLSTB                  STV090x_Px_MODCODLSTB(2)
+#define STV090x_OFFST_Px_DIS_QP_5_6_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_5_6_FIELD      4
+#define STV090x_OFFST_Px_DIS_QP_4_5_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_4_5_FIELD      4
+
+#define STV090x_Px_MODCODLSTC(__x)             (0xf4bc - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTC                  STV090x_Px_MODCODLSTC(1)
+#define STV090x_P2_MODCODLSTC                  STV090x_Px_MODCODLSTC(2)
+#define STV090x_OFFST_Px_DIS_QP_3_4_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_3_4_FIELD      4
+#define STV090x_OFFST_Px_DIS_QP_2_3_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_2_3_FIELD      4
+
+#define STV090x_Px_MODCODLSTD(__x)             (0xf4bd - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTD                  STV090x_Px_MODCODLSTD(1)
+#define STV090x_P2_MODCODLSTD                  STV090x_Px_MODCODLSTD(2)
+#define STV090x_OFFST_Px_DIS_QP_3_5_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_3_5_FIELD      4
+#define STV090x_OFFST_Px_DIS_QP_1_2_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_1_2_FIELD      4
+
+#define STV090x_Px_MODCODLSTE(__x)             (0xf4be - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTE                  STV090x_Px_MODCODLSTE(1)
+#define STV090x_P2_MODCODLSTE                  STV090x_Px_MODCODLSTE(2)
+#define STV090x_OFFST_Px_DIS_QP_2_5_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_2_5_FIELD      4
+#define STV090x_OFFST_Px_DIS_QP_1_3_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_1_3_FIELD      4
+
+#define STV090x_Px_MODCODLSTF(__x)             (0xf4bf - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTF                  STV090x_Px_MODCODLSTF(1)
+#define STV090x_P2_MODCODLSTF                  STV090x_Px_MODCODLSTF(2)
+#define STV090x_OFFST_Px_DIS_QP_1_4_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_1_4_FIELD      4
+
+#define STV090x_Px_GAUSSR0(__x)                        (0xf4c0 - (__x - 1) * 0x200)
+#define STV090x_P1_GAUSSR0                     STV090x_Px_GAUSSR0(1)
+#define STV090x_P2_GAUSSR0                     STV090x_Px_GAUSSR0(2)
+#define STV090x_OFFST_Px_EN_CCIMODE_FIELD      7
+#define STV090x_WIDTH_Px_EN_CCIMODE_FIELD      1
+#define STV090x_OFFST_Px_R0_GAUSSIEN_FIELD     0
+#define STV090x_WIDTH_Px_R0_GAUSSIEN_FIELD     7
+
+#define STV090x_Px_CCIR0(__x)                  (0xf4c1 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIR0                       STV090x_Px_CCIR0(1)
+#define STV090x_P2_CCIR0                       STV090x_Px_CCIR0(2)
+#define STV090x_OFFST_Px_CCIDETECT_PLH_FIELD   7
+#define STV090x_WIDTH_Px_CCIDETECT_PLH_FIELD   1
+#define STV090x_OFFST_Px_R0_CCI_FIELD          0
+#define STV090x_WIDTH_Px_R0_CCI_FIELD          7
+
+#define STV090x_Px_CCIQUANT(__x)               (0xf4c2 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIQUANT                    STV090x_Px_CCIQUANT(1)
+#define STV090x_P2_CCIQUANT                    STV090x_Px_CCIQUANT(2)
+#define STV090x_OFFST_Px_CCI_BETA_FIELD                5
+#define STV090x_WIDTH_Px_CCI_BETA_FIELD                3
+#define STV090x_OFFST_Px_CCI_QUANT_FIELD       0
+#define STV090x_WIDTH_Px_CCI_QUANT_FIELD       5
+
+#define STV090x_Px_CCITHRESH(__x)              (0xf4c3 - (__x - 1) * 0x200)
+#define STV090x_P1_CCITHRESH                   STV090x_Px_CCITHRESH(1)
+#define STV090x_P2_CCITHRESH                   STV090x_Px_CCITHRESH(2)
+#define STV090x_OFFST_Px_CCI_THRESHOLD_FIELD   0
+#define STV090x_WIDTH_Px_CCI_THRESHOLD_FIELD   8
+
+#define STV090x_Px_CCIACC(__x)                 (0xf4c4 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIACC                      STV090x_Px_CCIACC(1)
+#define STV090x_P2_CCIACC                      STV090x_Px_CCIACC(1)
+#define STV090x_OFFST_Px_CCI_VALUE_FIELD       0
+#define STV090x_WIDTH_Px_CCI_VALUE_FIELD       8
+
+#define STV090x_Px_DMDRESCFG(__x)              (0xF4C6 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDRESCFG                   STV090x_Px_DMDRESCFG(1)
+#define STV090x_P2_DMDRESCFG                   STV090x_Px_DMDRESCFG(2)
+#define STV090x_OFFST_Px_DMDRES_RESET_FIELD    7
+#define STV090x_WIDTH_Px_DMDRES_RESET_FIELD    1
+
+#define STV090x_Px_DMDRESADR(__x)              (0xF4C7 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDRESADR                   STV090x_Px_DMDRESADR(1)
+#define STV090x_P2_DMDRESADR                   STV090x_Px_DMDRESADR(2)
+#define STV090x_OFFST_Px_DMDRES_RESNBR_FIELD   0
+#define STV090x_WIDTH_Px_DMDRES_RESNBR_FIELD   4
+
+#define STV090x_Px_DMDRESDATAy(__x, __y)       (0xF4C8 - (__x - 1) * 0x200 + (7 - __y))
+#define STV090x_P1_DMDRESDATA0                 STV090x_Px_DMDRESDATAy(1, 0)
+#define STV090x_P1_DMDRESDATA1                 STV090x_Px_DMDRESDATAy(1, 1)
+#define STV090x_P1_DMDRESDATA2                 STV090x_Px_DMDRESDATAy(1, 2)
+#define STV090x_P1_DMDRESDATA3                 STV090x_Px_DMDRESDATAy(1, 3)
+#define STV090x_P1_DMDRESDATA4                 STV090x_Px_DMDRESDATAy(1, 4)
+#define STV090x_P1_DMDRESDATA5                 STV090x_Px_DMDRESDATAy(1, 5)
+#define STV090x_P1_DMDRESDATA6                 STV090x_Px_DMDRESDATAy(1, 6)
+#define STV090x_P1_DMDRESDATA7                 STV090x_Px_DMDRESDATAy(1, 7)
+#define STV090x_P2_DMDRESDATA0                 STV090x_Px_DMDRESDATAy(2, 0)
+#define STV090x_P2_DMDRESDATA1                 STV090x_Px_DMDRESDATAy(2, 1)
+#define STV090x_P2_DMDRESDATA2                 STV090x_Px_DMDRESDATAy(2, 2)
+#define STV090x_P2_DMDRESDATA3                 STV090x_Px_DMDRESDATAy(2, 3)
+#define STV090x_P2_DMDRESDATA4                 STV090x_Px_DMDRESDATAy(2, 4)
+#define STV090x_P2_DMDRESDATA5                 STV090x_Px_DMDRESDATAy(2, 5)
+#define STV090x_P2_DMDRESDATA6                 STV090x_Px_DMDRESDATAy(2, 6)
+#define STV090x_P2_DMDRESDATA7                 STV090x_Px_DMDRESDATAy(2, 7)
+#define STV090x_OFFST_Px_DMDRES_DATA_FIELD     0
+#define STV090x_WIDTH_Px_DMDRES_DATA_FIELD     8
+
+#define STV090x_Px_FFEIy(__x, __y)             (0xf4d0 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
+#define STV090x_P1_FFEI1                       STV090x_Px_FFEIy(1, 1)
+#define STV090x_P1_FFEI2                       STV090x_Px_FFEIy(1, 2)
+#define STV090x_P1_FFEI3                       STV090x_Px_FFEIy(1, 3)
+#define STV090x_P1_FFEI4                       STV090x_Px_FFEIy(1, 4)
+#define STV090x_P2_FFEI1                       STV090x_Px_FFEIy(2, 1)
+#define STV090x_P2_FFEI2                       STV090x_Px_FFEIy(2, 2)
+#define STV090x_P2_FFEI3                       STV090x_Px_FFEIy(2, 3)
+#define STV090x_P2_FFEI4                       STV090x_Px_FFEIy(2, 4)
+#define STV090x_OFFST_Px_FFE_ACCIy_FIELD       0
+#define STV090x_WIDTH_Px_FFE_ACCIy_FIELD       8
+
+#define STV090x_Px_FFEQy(__x, __y)             (0xf4d1 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
+#define STV090x_P1_FFEQ1                       STV090x_Px_FFEQy(1, 1)
+#define STV090x_P1_FFEQ2                       STV090x_Px_FFEQy(1, 2)
+#define STV090x_P1_FFEQ3                       STV090x_Px_FFEQy(1, 3)
+#define STV090x_P1_FFEQ4                       STV090x_Px_FFEQy(1, 4)
+#define STV090x_P2_FFEQ1                       STV090x_Px_FFEQy(2, 1)
+#define STV090x_P2_FFEQ2                       STV090x_Px_FFEQy(2, 2)
+#define STV090x_P2_FFEQ3                       STV090x_Px_FFEQy(2, 3)
+#define STV090x_P2_FFEQ4                       STV090x_Px_FFEQy(2, 4)
+#define STV090x_OFFST_Px_FFE_ACCQy_FIELD       0
+#define STV090x_WIDTH_Px_FFE_ACCQy_FIELD       8
+
+#define STV090x_Px_FFECFG(__x)                 (0xf4d8 - (__x - 1) * 0x200)
+#define STV090x_P1_FFECFG                      STV090x_Px_FFECFG(1)
+#define STV090x_P2_FFECFG                      STV090x_Px_FFECFG(2)
+#define STV090x_OFFST_Px_EQUALFFE_ON_FIELD     6
+#define STV090x_WIDTH_Px_EQUALFFE_ON_FIELD     1
+
+#define STV090x_Px_SMAPCOEF7(__x)              (0xf500 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF7                   STV090x_Px_SMAPCOEF7(1)
+#define STV090x_P2_SMAPCOEF7                   STV090x_Px_SMAPCOEF7(2)
+#define STV090x_OFFST_Px_DIS_QSCALE_FIELD      7
+#define STV090x_WIDTH_Px_DIS_QSCALE_FIELD      1
+#define STV090x_OFFST_Px_SMAPCOEF_Q_LLR12_FIELD        0
+#define STV090x_WIDTH_Px_SMAPCOEF_Q_LLR12_FIELD        7
+
+#define STV090x_Px_SMAPCOEF6(__x)              (0xf501 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF6                   STV090x_Px_SMAPCOEF6(1)
+#define STV090x_P2_SMAPCOEF6                   STV090x_Px_SMAPCOEF6(2)
+#define STV090x_OFFST_Px_ADJ_8PSKLLR1_FIELD    2
+#define STV090x_WIDTH_Px_ADJ_8PSKLLR1_FIELD    1
+#define STV090x_OFFST_Px_OLD_8PSKLLR1_FIELD    1
+#define STV090x_WIDTH_Px_OLD_8PSKLLR1_FIELD    1
+#define STV090x_OFFST_Px_DIS_AB8PSK_FIELD      0
+#define STV090x_WIDTH_Px_DIS_AB8PSK_FIELD      1
+
+#define STV090x_Px_SMAPCOEF5(__x)                      (0xf502 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF5                           STV090x_Px_SMAPCOEF5(1)
+#define STV090x_P2_SMAPCOEF5                           STV090x_Px_SMAPCOEF5(2)
+#define STV090x_OFFST_Px_DIS_8SCALE_FIELD              7
+#define STV090x_WIDTH_Px_DIS_8SCALE_FIELD              1
+#define STV090x_OFFST_Px_SMAPCOEF_8P_LLR23_FIELD       0
+#define STV090x_WIDTH_Px_SMAPCOEF_8P_LLR23_FIELD       7
+
+#define STV090x_Px_DMDPLHSTAT(__x)             (0xF520 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDPLHSTAT                  STV090x_Px_DMDPLHSTAT(1)
+#define STV090x_P2_DMDPLHSTAT                  STV090x_Px_DMDPLHSTAT(2)
+#define STV090x_OFFST_Px_PLH_STATISTIC_FIELD   0
+#define STV090x_WIDTH_Px_PLH_STATISTIC_FIELD   8
+
+#define STV090x_Px_LOCKTIMEy(__x, __y)         (0xF525 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_LOCKTIME0                   STV090x_Px_LOCKTIMEy(1, 0)
+#define STV090x_P1_LOCKTIME1                   STV090x_Px_LOCKTIMEy(1, 1)
+#define STV090x_P1_LOCKTIME2                   STV090x_Px_LOCKTIMEy(1, 2)
+#define STV090x_P1_LOCKTIME3                   STV090x_Px_LOCKTIMEy(1, 3)
+#define STV090x_P2_LOCKTIME0                   STV090x_Px_LOCKTIMEy(2, 0)
+#define STV090x_P2_LOCKTIME1                   STV090x_Px_LOCKTIMEy(2, 1)
+#define STV090x_P2_LOCKTIME2                   STV090x_Px_LOCKTIMEy(2, 2)
+#define STV090x_P2_LOCKTIME3                   STV090x_Px_LOCKTIMEy(2, 3)
+#define STV090x_OFFST_Px_DEMOD_LOCKTIME_FIELD  0
+#define STV090x_WIDTH_Px_DEMOD_LOCKTIME_FIELD  8
+
+#define STV090x_Px_TNRCFG(__x)                 (0xf4e0 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_TNRCFG                      STV090x_Px_TNRCFG(1)
+#define STV090x_P2_TNRCFG                      STV090x_Px_TNRCFG(2)
+
+#define STV090x_Px_TNRCFG2(__x)                        (0xf4e1 - (__x - 1) * 0x200)
+#define STV090x_P1_TNRCFG2                     STV090x_Px_TNRCFG2(1)
+#define STV090x_P2_TNRCFG2                     STV090x_Px_TNRCFG2(2)
+#define STV090x_OFFST_Px_TUN_IQSWAP_FIELD      7
+#define STV090x_WIDTH_Px_TUN_IQSWAP_FIELD      1
+
+#define STV090x_Px_VITSCALE(__x)               (0xf532 - (__x - 1) * 0x200)
+#define STV090x_P1_VITSCALE                    STV090x_Px_VITSCALE(1)
+#define STV090x_P2_VITSCALE                    STV090x_Px_VITSCALE(2)
+#define STV090x_OFFST_Px_NVTH_NOSRANGE_FIELD   7
+#define STV090x_WIDTH_Px_NVTH_NOSRANGE_FIELD   1
+#define STV090x_OFFST_Px_VERROR_MAXMODE_FIELD  6
+#define STV090x_WIDTH_Px_VERROR_MAXMODE_FIELD  1
+#define STV090x_OFFST_Px_NSLOWSN_LOCKED_FIELD  3
+#define STV090x_WIDTH_Px_NSLOWSN_LOCKED_FIELD  1
+#define STV090x_OFFST_Px_DIS_RSFLOCK_FIELD     1
+#define STV090x_WIDTH_Px_DIS_RSFLOCK_FIELD     1
+
+#define STV090x_Px_FECM(__x)                   (0xf533 - (__x - 1) * 0x200)
+#define STV090x_P1_FECM                                STV090x_Px_FECM(1)
+#define STV090x_P2_FECM                                STV090x_Px_FECM(2)
+#define STV090x_OFFST_Px_DSS_DVB_FIELD         7
+#define STV090x_WIDTH_Px_DSS_DVB_FIELD         1
+#define STV090x_OFFST_Px_DSS_SRCH_FIELD                4
+#define STV090x_WIDTH_Px_DSS_SRCH_FIELD                1
+#define STV090x_OFFST_Px_SYNCVIT_FIELD         1
+#define STV090x_WIDTH_Px_SYNCVIT_FIELD         1
+#define STV090x_OFFST_Px_IQINV_FIELD           0
+#define STV090x_WIDTH_Px_IQINV_FIELD           1
+
+#define STV090x_Px_VTH12(__x)                  (0xf534 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH12                       STV090x_Px_VTH12(1)
+#define STV090x_P2_VTH12                       STV090x_Px_VTH12(2)
+#define STV090x_OFFST_Px_VTH12_FIELD           0
+#define STV090x_WIDTH_Px_VTH12_FIELD           8
+
+#define STV090x_Px_VTH23(__x)                  (0xf535 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH23                       STV090x_Px_VTH23(1)
+#define STV090x_P2_VTH23                       STV090x_Px_VTH23(2)
+#define STV090x_OFFST_Px_VTH23_FIELD           0
+#define STV090x_WIDTH_Px_VTH23_FIELD           8
+
+#define STV090x_Px_VTH34(__x)                  (0xf536 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH34                       STV090x_Px_VTH34(1)
+#define STV090x_P2_VTH34                       STV090x_Px_VTH34(2)
+#define STV090x_OFFST_Px_VTH34_FIELD           0
+#define STV090x_WIDTH_Px_VTH34_FIELD           8
+
+#define STV090x_Px_VTH56(__x)                  (0xf537 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH56                       STV090x_Px_VTH56(1)
+#define STV090x_P2_VTH56                       STV090x_Px_VTH56(2)
+#define STV090x_OFFST_Px_VTH56_FIELD           0
+#define STV090x_WIDTH_Px_VTH56_FIELD           8
+
+#define STV090x_Px_VTH67(__x)                  (0xf538 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH67                       STV090x_Px_VTH67(1)
+#define STV090x_P2_VTH67                       STV090x_Px_VTH67(2)
+#define STV090x_OFFST_Px_VTH67_FIELD           0
+#define STV090x_WIDTH_Px_VTH67_FIELD           8
+
+#define STV090x_Px_VTH78(__x)                  (0xf539 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH78                       STV090x_Px_VTH78(1)
+#define STV090x_P2_VTH78                       STV090x_Px_VTH78(2)
+#define STV090x_OFFST_Px_VTH78_FIELD           0
+#define STV090x_WIDTH_Px_VTH78_FIELD           8
+
+#define STV090x_Px_VITCURPUN(__x)              (0xf53a - (__x - 1) * 0x200)
+#define STV090x_P1_VITCURPUN                   STV090x_Px_VITCURPUN(1)
+#define STV090x_P2_VITCURPUN                   STV090x_Px_VITCURPUN(2)
+#define STV090x_OFFST_Px_VIT_CURPUN_FIELD      0
+#define STV090x_WIDTH_Px_VIT_CURPUN_FIELD      5
+
+#define STV090x_Px_VERROR(__x)                 (0xf53b - (__x - 1) * 0x200)
+#define STV090x_P1_VERROR                      STV090x_Px_VERROR(1)
+#define STV090x_P2_VERROR                      STV090x_Px_VERROR(2)
+#define STV090x_OFFST_Px_REGERR_VIT_FIELD      0
+#define STV090x_WIDTH_Px_REGERR_VIT_FIELD      8
+
+#define STV090x_Px_PRVIT(__x)                  (0xf53c - (__x - 1) * 0x200)
+#define STV090x_P1_PRVIT                       STV090x_Px_PRVIT(1)
+#define STV090x_P2_PRVIT                       STV090x_Px_PRVIT(2)
+#define STV090x_OFFST_Px_DIS_VTHLOCK_FIELD     6
+#define STV090x_WIDTH_Px_DIS_VTHLOCK_FIELD     1
+#define STV090x_OFFST_Px_E7_8VIT_FIELD         5
+#define STV090x_WIDTH_Px_E7_8VIT_FIELD         1
+#define STV090x_OFFST_Px_E6_7VIT_FIELD         4
+#define STV090x_WIDTH_Px_E6_7VIT_FIELD         1
+#define STV090x_OFFST_Px_E5_6VIT_FIELD         3
+#define STV090x_WIDTH_Px_E5_6VIT_FIELD         1
+#define STV090x_OFFST_Px_E3_4VIT_FIELD         2
+#define STV090x_WIDTH_Px_E3_4VIT_FIELD         1
+#define STV090x_OFFST_Px_E2_3VIT_FIELD         1
+#define STV090x_WIDTH_Px_E2_3VIT_FIELD         1
+#define STV090x_OFFST_Px_E1_2VIT_FIELD         0
+#define STV090x_WIDTH_Px_E1_2VIT_FIELD         1
+
+#define STV090x_Px_VAVSRVIT(__x)               (0xf53d - (__x - 1) * 0x200)
+#define STV090x_P1_VAVSRVIT                    STV090x_Px_VAVSRVIT(1)
+#define STV090x_P2_VAVSRVIT                    STV090x_Px_VAVSRVIT(2)
+#define STV090x_OFFST_Px_SNVIT_FIELD           4
+#define STV090x_WIDTH_Px_SNVIT_FIELD           2
+#define STV090x_OFFST_Px_TOVVIT_FIELD          2
+#define STV090x_WIDTH_Px_TOVVIT_FIELD          2
+#define STV090x_OFFST_Px_HYPVIT_FIELD          0
+#define STV090x_WIDTH_Px_HYPVIT_FIELD          2
+
+#define STV090x_Px_VSTATUSVIT(__x)             (0xf53e - (__x - 1) * 0x200)
+#define STV090x_P1_VSTATUSVIT                  STV090x_Px_VSTATUSVIT(1)
+#define STV090x_P2_VSTATUSVIT                  STV090x_Px_VSTATUSVIT(2)
+#define STV090x_OFFST_Px_PRFVIT_FIELD          4
+#define STV090x_WIDTH_Px_PRFVIT_FIELD          1
+#define STV090x_OFFST_Px_LOCKEDVIT_FIELD       3
+#define STV090x_WIDTH_Px_LOCKEDVIT_FIELD       1
+
+#define STV090x_Px_VTHINUSE(__x)               (0xf53f - (__x - 1) * 0x200)
+#define STV090x_P1_VTHINUSE                    STV090x_Px_VTHINUSE(1)
+#define STV090x_P2_VTHINUSE                    STV090x_Px_VTHINUSE(2)
+#define STV090x_OFFST_Px_VIT_INUSE_FIELD       0
+#define STV090x_WIDTH_Px_VIT_INUSE_FIELD       8
+
+#define STV090x_Px_KDIV12(__x)                 (0xf540 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV12                      STV090x_Px_KDIV12(1)
+#define STV090x_P2_KDIV12                      STV090x_Px_KDIV12(2)
+#define STV090x_OFFST_Px_K_DIVIDER_12_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_12_FIELD    7
+
+#define STV090x_Px_KDIV23(__x)                 (0xf541 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV23                      STV090x_Px_KDIV23(1)
+#define STV090x_P2_KDIV23                      STV090x_Px_KDIV23(2)
+#define STV090x_OFFST_Px_K_DIVIDER_23_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_23_FIELD    7
+
+#define STV090x_Px_KDIV34(__x)                 (0xf542 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV34                      STV090x_Px_KDIV34(1)
+#define STV090x_P2_KDIV34                      STV090x_Px_KDIV34(2)
+#define STV090x_OFFST_Px_K_DIVIDER_34_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_34_FIELD    7
+
+#define STV090x_Px_KDIV56(__x)                 (0xf543 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV56                      STV090x_Px_KDIV56(1)
+#define STV090x_P2_KDIV56                      STV090x_Px_KDIV56(2)
+#define STV090x_OFFST_Px_K_DIVIDER_56_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_56_FIELD    7
+
+#define STV090x_Px_KDIV67(__x)                 (0xf544 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV67                      STV090x_Px_KDIV67(1)
+#define STV090x_P2_KDIV67                      STV090x_Px_KDIV67(2)
+#define STV090x_OFFST_Px_K_DIVIDER_67_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_67_FIELD    7
+
+#define STV090x_Px_KDIV78(__x)                 (0xf545 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV78                      STV090x_Px_KDIV78(1)
+#define STV090x_P2_KDIV78                      STV090x_Px_KDIV78(2)
+#define STV090x_OFFST_Px_K_DIVIDER_78_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_78_FIELD    7
+
+#define STV090x_Px_PDELCTRL1(__x)              (0xf550 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELCTRL1                   STV090x_Px_PDELCTRL1(1)
+#define STV090x_P2_PDELCTRL1                   STV090x_Px_PDELCTRL1(2)
+#define STV090x_OFFST_Px_INV_MISMASK_FIELD     7
+#define STV090x_WIDTH_Px_INV_MISMASK_FIELD     1
+#define STV090x_OFFST_Px_FILTER_EN_FIELD       5
+#define STV090x_WIDTH_Px_FILTER_EN_FIELD       1
+#define STV090x_OFFST_Px_EN_MIS00_FIELD                1
+#define STV090x_WIDTH_Px_EN_MIS00_FIELD                1
+#define STV090x_OFFST_Px_ALGOSWRST_FIELD       0
+#define STV090x_WIDTH_Px_ALGOSWRST_FIELD       1
+
+#define STV090x_Px_PDELCTRL2(__x)              (0xf551 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELCTRL2                   STV090x_Px_PDELCTRL2(1)
+#define STV090x_P2_PDELCTRL2                   STV090x_Px_PDELCTRL2(2)
+#define STV090x_OFFST_Px_FORCE_CONTINUOUS      7
+#define STV090x_WIDTH_Px_FORCE_CONTINUOUS      1
+#define STV090x_OFFST_Px_RESET_UPKO_COUNT      6
+#define STV090x_WIDTH_Px_RESET_UPKO_COUNT      1
+#define STV090x_OFFST_Px_USER_PKTDELIN_NB      5
+#define STV090x_WIDTH_Px_USER_PKTDELIN_NB      1
+#define STV090x_OFFST_Px_FORCE_LOCKED          4
+#define STV090x_WIDTH_Px_FORCE_LOCKED          1
+#define STV090x_OFFST_Px_DATA_UNBBSCRAM                3
+#define STV090x_WIDTH_Px_DATA_UNBBSCRAM                1
+#define STV090x_OFFST_Px_FORCE_LONGPACKET      2
+#define STV090x_WIDTH_Px_FORCE_LONGPACKET      1
+#define STV090x_OFFST_Px_FRAME_MODE_FIELD      1
+#define STV090x_WIDTH_Px_FRAME_MODE_FIELD      1
+
+#define STV090x_Px_HYSTTHRESH(__x)             (0xf554 - (__x - 1) * 0x200)
+#define STV090x_P1_HYSTTHRESH                  STV090x_Px_HYSTTHRESH(1)
+#define STV090x_P2_HYSTTHRESH                  STV090x_Px_HYSTTHRESH(2)
+#define STV090x_OFFST_Px_UNLCK_THRESH_FIELD    4
+#define STV090x_WIDTH_Px_UNLCK_THRESH_FIELD    4
+#define STV090x_OFFST_Px_DELIN_LCK_THRESH_FIELD        0
+#define STV090x_WIDTH_Px_DELIN_LCK_THRESH_FIELD        4
+
+#define STV090x_Px_ISIENTRY(__x)               (0xf55e - (__x - 1) * 0x200)
+#define STV090x_P1_ISIENTRY                    STV090x_Px_ISIENTRY(1)
+#define STV090x_P2_ISIENTRY                    STV090x_Px_ISIENTRY(2)
+#define STV090x_OFFST_Px_ISI_ENTRY_FIELD       0
+#define STV090x_WIDTH_Px_ISI_ENTRY_FIELD       8
+
+#define STV090x_Px_ISIBITENA(__x)              (0xf55f - (__x - 1) * 0x200)
+#define STV090x_P1_ISIBITENA                   STV090x_Px_ISIBITENA(1)
+#define STV090x_P2_ISIBITENA                   STV090x_Px_ISIBITENA(2)
+#define STV090x_OFFST_Px_ISI_BIT_EN_FIELD      0
+#define STV090x_WIDTH_Px_ISI_BIT_EN_FIELD      8
+
+#define STV090x_Px_MATSTRy(__x, __y)           (0xf561 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_MATSTR0                     STV090x_Px_MATSTRy(1, 0)
+#define STV090x_P1_MATSTR1                     STV090x_Px_MATSTRy(1, 1)
+#define STV090x_P2_MATSTR0                     STV090x_Px_MATSTRy(2, 0)
+#define STV090x_P2_MATSTR1                     STV090x_Px_MATSTRy(2, 1)
+#define STV090x_OFFST_Px_MATYPE_CURRENT_FIELD  0
+#define STV090x_WIDTH_Px_MATYPE_CURRENT_FIELD  8
+
+#define STV090x_Px_UPLSTRy(__x, __y)           (0xf563 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_UPLSTR0                     STV090x_Px_UPLSTRy(1, 0)
+#define STV090x_P1_UPLSTR1                     STV090x_Px_UPLSTRy(1, 1)
+#define STV090x_P2_UPLSTR0                     STV090x_Px_UPLSTRy(2, 0)
+#define STV090x_P2_UPLSTR1                     STV090x_Px_UPLSTRy(2, 1)
+#define STV090x_OFFST_Px_UPL_CURRENT_FIELD     0
+#define STV090x_WIDTH_Px_UPL_CURRENT_FIELD     8
+
+#define STV090x_Px_DFLSTRy(__x, __y)           (0xf565 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_DFLSTR0                     STV090x_Px_DFLSTRy(1, 0)
+#define STV090x_P1_DFLSTR1                     STV090x_Px_DFLSTRy(1, 1)
+#define STV090x_P2_DFLSTR0                     STV090x_Px_DFLSTRy(2, 0)
+#define STV090x_P2_DFLSTR1                     STV090x_Px_DFLSTRy(2, 1)
+#define STV090x_OFFST_Px_DFL_CURRENT_FIELD     0
+#define STV090x_WIDTH_Px_DFL_CURRENT_FIELD     8
+
+#define STV090x_Px_SYNCSTR(__x)                        (0xf566 - (__x - 1) * 0x200)
+#define STV090x_P1_SYNCSTR                     STV090x_Px_SYNCSTR(1)
+#define STV090x_P2_SYNCSTR                     STV090x_Px_SYNCSTR(2)
+#define STV090x_OFFST_Px_SYNC_CURRENT_FIELD    0
+#define STV090x_WIDTH_Px_SYNC_CURRENT_FIELD    8
+
+#define STV090x_Px_SYNCDSTRy(__x, __y)         (0xf568 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_SYNCDSTR0                   STV090x_Px_SYNCDSTRy(1, 0)
+#define STV090x_P1_SYNCDSTR1                   STV090x_Px_SYNCDSTRy(1, 1)
+#define STV090x_P2_SYNCDSTR0                   STV090x_Px_SYNCDSTRy(2, 0)
+#define STV090x_P2_SYNCDSTR1                   STV090x_Px_SYNCDSTRy(2, 1)
+#define STV090x_OFFST_Px_SYNCD_CURRENT_FIELD   0
+#define STV090x_WIDTH_Px_SYNCD_CURRENT_FIELD   8
+
+#define STV090x_Px_PDELSTATUS1(__x)            (0xf569 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELSTATUS1                 STV090x_Px_PDELSTATUS1(1)
+#define STV090x_P2_PDELSTATUS1                 STV090x_Px_PDELSTATUS1(2)
+#define STV090x_OFFST_Px_PKTDELIN_LOCK_FIELD   1
+#define STV090x_WIDTH_Px_PKTDELIN_LOCK_FIELD   1
+#define STV090x_OFFST_Px_FIRST_LOCK_FIELD      0
+#define STV090x_WIDTH_Px_FIRST_LOCK_FIELD      1
+
+#define STV090x_Px_PDELSTATUS2(__x)            (0xf56a - (__x - 1) * 0x200)
+#define STV090x_P1_PDELSTATUS2                 STV090x_Px_PDELSTATUS2(1)
+#define STV090x_P2_PDELSTATUS2                 STV090x_Px_PDELSTATUS2(2)
+#define STV090x_OFFST_Px_FRAME_MODCOD_FIELD    2
+#define STV090x_WIDTH_Px_FRAME_MODCOD_FIELD    5
+#define STV090x_OFFST_Px_FRAME_TYPE_FIELD      0
+#define STV090x_WIDTH_Px_FRAME_TYPE_FIELD      2
+
+#define STV090x_Px_BBFCRCKO1(__x)              (0xf56b - (__x - 1) * 0x200)
+#define STV090x_P1_BBFCRCKO1                   STV090x_Px_BBFCRCKO1(1)
+#define STV090x_P2_BBFCRCKO1                   STV090x_Px_BBFCRCKO1(2)
+#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD    0
+#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD    8
+
+#define STV090x_Px_BBFCRCKO0(__x)              (0xf56c - (__x - 1) * 0x200)
+#define STV090x_P1_BBFCRCKO0                   STV090x_Px_BBFCRCKO0(1)
+#define STV090x_P2_BBFCRCKO0                   STV090x_Px_BBFCRCKO0(2)
+#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD    0
+#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD    8
+
+#define STV090x_Px_UPCRCKO1(__x)               (0xf56d - (__x - 1) * 0x200)
+#define STV090x_P1_UPCRCKO1                    STV090x_Px_UPCRCKO1(1)
+#define STV090x_P2_UPCRCKO1                    STV090x_Px_UPCRCKO1(2)
+#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD    0
+#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD    8
+
+#define STV090x_Px_UPCRCKO0(__x)               (0xf56e - (__x - 1) * 0x200)
+#define STV090x_P1_UPCRCKO0                    STV090x_Px_UPCRCKO0(1)
+#define STV090x_P2_UPCRCKO0                    STV090x_Px_UPCRCKO0(2)
+#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD    0
+#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD    8
+
+#define STV090x_NBITER_NFx(__x)                                (0xFA03 + (__x - 4) * 0x1)
+#define STV090x_NBITER_NF4                             STV090x_NBITER_NFx(4)
+#define STV090x_NBITER_NF5                             STV090x_NBITER_NFx(5)
+#define STV090x_NBITER_NF6                             STV090x_NBITER_NFx(6)
+#define STV090x_NBITER_NF7                             STV090x_NBITER_NFx(7)
+#define STV090x_NBITER_NF8                             STV090x_NBITER_NFx(8)
+#define STV090x_NBITER_NF9                             STV090x_NBITER_NFx(9)
+#define STV090x_NBITER_NF10                            STV090x_NBITER_NFx(10)
+#define STV090x_NBITER_NF11                            STV090x_NBITER_NFx(11)
+#define STV090x_NBITER_NF12                            STV090x_NBITER_NFx(12)
+#define STV090x_NBITER_NF13                            STV090x_NBITER_NFx(13)
+#define STV090x_NBITER_NF14                            STV090x_NBITER_NFx(14)
+#define STV090x_NBITER_NF15                            STV090x_NBITER_NFx(15)
+#define STV090x_NBITER_NF16                            STV090x_NBITER_NFx(16)
+#define STV090x_NBITER_NF17                            STV090x_NBITER_NFx(17)
+
+#define STV090x_NBITERNOERR                            0xFA3F
+#define STV090x_OFFST_NBITER_STOP_CRIT_FIELD           0
+#define STV090x_WIDTH_NBITER_STOP_CRIT_FIELD           4
+
+#define STV090x_GAINLLR_NFx(__x)                       (0xFA43 + (__x - 4) * 0x1)
+#define STV090x_GAINLLR_NF4                            STV090x_GAINLLR_NFx(4)
+#define STV090x_OFFST_GAINLLR_NF_QP_1_2_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_1_2_FIELD          7
+
+#define STV090x_GAINLLR_NF5                            STV090x_GAINLLR_NFx(5)
+#define STV090x_OFFST_GAINLLR_NF_QP_3_5_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_3_5_FIELD          7
+
+#define STV090x_GAINLLR_NF6                            STV090x_GAINLLR_NFx(6)
+#define STV090x_OFFST_GAINLLR_NF_QP_2_3_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_2_3_FIELD          7
+
+#define STV090x_GAINLLR_NF7                            STV090x_GAINLLR_NFx(7)
+#define STV090x_OFFST_GAINLLR_NF_QP_3_4_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_3_4_FIELD          7
+
+#define STV090x_GAINLLR_NF8                            STV090x_GAINLLR_NFx(8)
+#define STV090x_OFFST_GAINLLR_NF_QP_4_5_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_4_5_FIELD          7
+
+#define STV090x_GAINLLR_NF9                            STV090x_GAINLLR_NFx(9)
+#define STV090x_OFFST_GAINLLR_NF_QP_5_6_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_5_6_FIELD          7
+
+#define STV090x_GAINLLR_NF10                           STV090x_GAINLLR_NFx(10)
+#define STV090x_OFFST_GAINLLR_NF_QP_8_9_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_8_9_FIELD          7
+
+#define STV090x_GAINLLR_NF11                           STV090x_GAINLLR_NFx(11)
+#define STV090x_OFFST_GAINLLR_NF_QP_9_10_FIELD         0
+#define STV090x_WIDTH_GAINLLR_NF_QP_9_10_FIELD         7
+
+#define STV090x_GAINLLR_NF12                           STV090x_GAINLLR_NFx(12)
+#define STV090x_OFFST_GAINLLR_NF_8P_3_5_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_3_5_FIELD          7
+
+#define STV090x_GAINLLR_NF13                           STV090x_GAINLLR_NFx(13)
+#define STV090x_OFFST_GAINLLR_NF_8P_2_3_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_2_3_FIELD          7
+
+#define STV090x_GAINLLR_NF14                           STV090x_GAINLLR_NFx(14)
+#define STV090x_OFFST_GAINLLR_NF_8P_3_4_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_3_4_FIELD          7
+
+#define STV090x_GAINLLR_NF15                           STV090x_GAINLLR_NFx(15)
+#define STV090x_OFFST_GAINLLR_NF_8P_5_6_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_5_6_FIELD          7
+
+#define STV090x_GAINLLR_NF16                           STV090x_GAINLLR_NFx(16)
+#define STV090x_OFFST_GAINLLR_NF_8P_8_9_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_8_9_FIELD          7
+
+#define STV090x_GAINLLR_NF17                           STV090x_GAINLLR_NFx(17)
+#define STV090x_OFFST_GAINLLR_NF_8P_9_10_FIELD         0
+#define STV090x_WIDTH_GAINLLR_NF_8P_9_10_FIELD         7
+
+#define STV090x_GENCFG                                 0xFA86
+#define STV090x_OFFST_BROADCAST_FIELD                  4
+#define STV090x_WIDTH_BROADCAST_FIELD                  1
+#define STV090x_OFFST_PRIORITY_FIELD                   1
+#define STV090x_WIDTH_PRIORITY_FIELD                   1
+#define STV090x_OFFST_DDEMOD_FIELD                     0
+#define STV090x_WIDTH_DDEMOD_FIELD                     1
+
+#define STV090x_LDPCERRx(__x)                          (0xFA97 - (__x  * 0x1))
+#define STV090x_LDPCERR0                               STV090x_LDPCERRx(0)
+#define STV090x_LDPCERR1                               STV090x_LDPCERRx(1)
+#define STV090x_OFFST_Px_LDPC_ERRORS_COUNTER_FIELD     0
+#define STV090x_WIDTH_Px_LDPC_ERRORS_COUNTER_FIELD     8
+
+#define STV090x_BCHERR                                 0xFA98
+#define STV090x_OFFST_Px_ERRORFLAG_FIELD               4
+#define STV090x_WIDTH_Px_ERRORFLAG_FIELD               1
+#define STV090x_OFFST_Px_BCH_ERRORS_COUNTER_FIELD      0
+#define STV090x_WIDTH_Px_BCH_ERRORS_COUNTER_FIELD      4
+
+#define STV090x_Px_TSSTATEM(__x)                       (0xF570 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATEM                            STV090x_Px_TSSTATEM(1)
+#define STV090x_P2_TSSTATEM                            STV090x_Px_TSSTATEM(2)
+#define STV090x_OFFST_Px_TSDIL_ON_FIELD                        7
+#define STV090x_WIDTH_Px_TSDIL_ON_FIELD                        1
+#define STV090x_OFFST_Px_TSRS_ON_FIELD                 5
+#define STV090x_WIDTH_Px_TSRS_ON_FIELD                 1
+
+#define STV090x_Px_TSCFGH(__x)                         (0xF572 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGH                              STV090x_Px_TSCFGH(1)
+#define STV090x_P2_TSCFGH                              STV090x_Px_TSCFGH(2)
+#define STV090x_OFFST_Px_TSFIFO_DVBCI_FIELD            7
+#define STV090x_WIDTH_Px_TSFIFO_DVBCI_FIELD            1
+#define STV090x_OFFST_Px_TSFIFO_SERIAL_FIELD           6
+#define STV090x_WIDTH_Px_TSFIFO_SERIAL_FIELD           1
+#define STV090x_OFFST_Px_TSFIFO_TEIUPDATE_FIELD                5
+#define STV090x_WIDTH_Px_TSFIFO_TEIUPDATE_FIELD                1
+#define STV090x_OFFST_Px_TSFIFO_DUTY50_FIELD           4
+#define STV090x_WIDTH_Px_TSFIFO_DUTY50_FIELD           1
+#define STV090x_OFFST_Px_TSFIFO_HSGNLOUT_FIELD         3
+#define STV090x_WIDTH_Px_TSFIFO_HSGNLOUT_FIELD         1
+#define STV090x_OFFST_Px_TSFIFO_ERRORMODE_FIELD                1
+#define STV090x_WIDTH_Px_TSFIFO_ERRORMODE_FIELD                2
+#define STV090x_OFFST_Px_RST_HWARE_FIELD               0
+#define STV090x_WIDTH_Px_RST_HWARE_FIELD               1
+
+#define STV090x_Px_TSCFGM(__x)                         (0xF573 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGM                              STV090x_Px_TSCFGM(1)
+#define STV090x_P2_TSCFGM                              STV090x_Px_TSCFGM(2)
+#define STV090x_OFFST_Px_TSFIFO_MANSPEED_FIELD         6
+#define STV090x_WIDTH_Px_TSFIFO_MANSPEED_FIELD         2
+#define STV090x_OFFST_Px_TSFIFO_PERMDATA_FIELD         5
+#define STV090x_WIDTH_Px_TSFIFO_PERMDATA_FIELD         1
+#define STV090x_OFFST_Px_TSFIFO_INVDATA_FIELD          0
+#define STV090x_WIDTH_Px_TSFIFO_INVDATA_FIELD          1
+
+#define STV090x_Px_TSCFGL(__x)                         (0xF574 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGL                              STV090x_Px_TSCFGL(1)
+#define STV090x_P2_TSCFGL                              STV090x_Px_TSCFGL(2)
+#define STV090x_OFFST_Px_TSFIFO_BCLKDEL1CK_FIELD       6
+#define STV090x_WIDTH_Px_TSFIFO_BCLKDEL1CK_FIELD       2
+#define STV090x_OFFST_Px_BCHERROR_MODE_FIELD           4
+#define STV090x_WIDTH_Px_BCHERROR_MODE_FIELD           2
+#define STV090x_OFFST_Px_TSFIFO_NSGNL2DATA_FIELD       3
+#define STV090x_WIDTH_Px_TSFIFO_NSGNL2DATA_FIELD       1
+#define STV090x_OFFST_Px_TSFIFO_EMBINDVB_FIELD         2
+#define STV090x_WIDTH_Px_TSFIFO_EMBINDVB_FIELD         1
+#define STV090x_OFFST_Px_TSFIFO_DPUNACT_FIELD          1
+#define STV090x_WIDTH_Px_TSFIFO_DPUNACT_FIELD          1
+
+#define STV090x_Px_TSINSDELH(__x)                      (0xF576 - (__x - 1) * 0x200)
+#define STV090x_P1_TSINSDELH                           STV090x_Px_TSINSDELH(1)
+#define STV090x_P2_TSINSDELH                           STV090x_Px_TSINSDELH(2)
+#define STV090x_OFFST_Px_TSDEL_SYNCBYTE_FIELD          7
+#define STV090x_WIDTH_Px_TSDEL_SYNCBYTE_FIELD          1
+#define STV090x_OFFST_Px_TSDEL_XXHEADER_FIELD          6
+#define STV090x_WIDTH_Px_TSDEL_XXHEADER_FIELD          1
+
+#define STV090x_Px_TSSPEED(__x)                                (0xF580 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSPEED                             STV090x_Px_TSSPEED(1)
+#define STV090x_P2_TSSPEED                             STV090x_Px_TSSPEED(2)
+#define STV090x_OFFST_Px_TSFIFO_OUTSPEED_FIELD         0
+#define STV090x_WIDTH_Px_TSFIFO_OUTSPEED_FIELD         8
+
+#define STV090x_Px_TSSTATUS(__x)                       (0xF581 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATUS                            STV090x_Px_TSSTATUS(1)
+#define STV090x_P2_TSSTATUS                            STV090x_Px_TSSTATUS(2)
+#define STV090x_OFFST_Px_TSFIFO_LINEOK_FIELD           7
+#define STV090x_WIDTH_Px_TSFIFO_LINEOK_FIELD           1
+#define STV090x_OFFST_Px_TSFIFO_ERROR_FIELD            6
+#define STV090x_WIDTH_Px_TSFIFO_ERROR_FIELD            1
+
+#define STV090x_Px_TSSTATUS2(__x)                      (0xF582 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATUS2                           STV090x_Px_TSSTATUS2(1)
+#define STV090x_P2_TSSTATUS2                           STV090x_Px_TSSTATUS2(2)
+#define STV090x_OFFST_Px_TSFIFO_DEMODSEL_FIELD         7
+#define STV090x_WIDTH_Px_TSFIFO_DEMODSEL_FIELD         1
+#define STV090x_OFFST_Px_TSFIFOSPEED_STORE_FIELD       6
+#define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD       1
+#define STV090x_OFFST_Px_DILXX_RESET_FIELD             5
+#define STV090x_WIDTH_Px_DILXX_RESET_FIELD             1
+#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD          5
+#define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD          1
+#define STV090x_OFFST_Px_SCRAMBDETECT_FIELD            1
+#define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD            1
+
+#define STV090x_Px_TSBITRATEy(__x, __y)                        (0xF584 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_TSBITRATE0                          STV090x_Px_TSBITRATEy(1, 0)
+#define STV090x_P1_TSBITRATE1                          STV090x_Px_TSBITRATEy(1, 1)
+#define STV090x_P2_TSBITRATE0                          STV090x_Px_TSBITRATEy(2, 0)
+#define STV090x_P2_TSBITRATE1                          STV090x_Px_TSBITRATEy(2, 1)
+#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD          7
+#define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD          8
+
+#define STV090x_Px_ERRCTRL1(__x)                       (0xF598 - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCTRL1                            STV090x_Px_ERRCTRL1(1)
+#define STV090x_P2_ERRCTRL1                            STV090x_Px_ERRCTRL1(2)
+#define STV090x_OFFST_Px_ERR_SOURCE_FIELD              4
+#define STV090x_WIDTH_Px_ERR_SOURCE_FIELD              4
+#define STV090x_OFFST_Px_NUM_EVENT_FIELD               0
+#define STV090x_WIDTH_Px_NUM_EVENT_FIELD               3
+
+#define STV090x_Px_ERRCNT12(__x)                       (0xF599 - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT12                            STV090x_Px_ERRCNT12(1)
+#define STV090x_P2_ERRCNT12                            STV090x_Px_ERRCNT12(2)
+#define STV090x_OFFST_Px_ERRCNT1_OLDVALUE_FIELD                7
+#define STV090x_WIDTH_Px_ERRCNT1_OLDVALUE_FIELD                1
+#define STV090x_OFFST_Px_ERR_CNT12_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT12_FIELD               7
+
+#define STV090x_Px_ERRCNT11(__x)                       (0xF59A - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT11                            STV090x_Px_ERRCNT11(1)
+#define STV090x_P2_ERRCNT11                            STV090x_Px_ERRCNT11(2)
+#define STV090x_OFFST_Px_ERR_CNT11_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT11_FIELD               8
+
+#define STV090x_Px_ERRCNT10(__x)                       (0xF59B - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT10                            STV090x_Px_ERRCNT10(1)
+#define STV090x_P2_ERRCNT10                            STV090x_Px_ERRCNT10(2)
+#define STV090x_OFFST_Px_ERR_CNT10_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT10_FIELD               8
+
+#define STV090x_Px_ERRCTRL2(__x)                       (0xF59C - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCTRL2                            STV090x_Px_ERRCTRL2(1)
+#define STV090x_P2_ERRCTRL2                            STV090x_Px_ERRCTRL2(2)
+#define STV090x_OFFST_Px_ERR_SOURCE2_FIELD             4
+#define STV090x_WIDTH_Px_ERR_SOURCE2_FIELD             4
+#define STV090x_OFFST_Px_NUM_EVENT2_FIELD              0
+#define STV090x_WIDTH_Px_NUM_EVENT2_FIELD              3
+
+#define STV090x_Px_ERRCNT22(__x)                       (0xF59D - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT22                            STV090x_Px_ERRCNT22(1)
+#define STV090x_P2_ERRCNT22                            STV090x_Px_ERRCNT22(2)
+#define STV090x_OFFST_Px_ERRCNT2_OLDVALUE_FIELD                7
+#define STV090x_WIDTH_Px_ERRCNT2_OLDVALUE_FIELD                1
+#define STV090x_OFFST_Px_ERR_CNT2_FIELD                        0
+#define STV090x_WIDTH_Px_ERR_CNT2_FIELD                        7
+
+#define STV090x_Px_ERRCNT21(__x)                       (0xF59E - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT21                            STV090x_Px_ERRCNT21(1)
+#define STV090x_P2_ERRCNT21                            STV090x_Px_ERRCNT21(2)
+#define STV090x_OFFST_Px_ERR_CNT21_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT21_FIELD               8
+
+#define STV090x_Px_ERRCNT20(__x)                       (0xF59F - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT20                            STV090x_Px_ERRCNT20(1)
+#define STV090x_P2_ERRCNT20                            STV090x_Px_ERRCNT20(2)
+#define STV090x_OFFST_Px_ERR_CNT20_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT20_FIELD               8
+
+#define STV090x_Px_FECSPY(__x)                         (0xF5A0 - (__x - 1) * 0x200)
+#define STV090x_P1_FECSPY                              STV090x_Px_FECSPY(1)
+#define STV090x_P2_FECSPY                              STV090x_Px_FECSPY(2)
+#define STV090x_OFFST_Px_SPY_ENABLE_FIELD              7
+#define STV090x_WIDTH_Px_SPY_ENABLE_FIELD              1
+#define STV090x_OFFST_Px_BERMETER_DATAMAODE_FIELD      2
+#define STV090x_WIDTH_Px_BERMETER_DATAMAODE_FIELD      2
+
+#define STV090x_Px_FSPYCFG(__x)                                (0xF5A1 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYCFG                             STV090x_Px_FSPYCFG(1)
+#define STV090x_P2_FSPYCFG                             STV090x_Px_FSPYCFG(2)
+#define STV090x_OFFST_Px_RST_ON_ERROR_FIELD            5
+#define STV090x_WIDTH_Px_RST_ON_ERROR_FIELD            1
+#define STV090x_OFFST_Px_ONE_SHOT_FIELD                        4
+#define STV090x_WIDTH_Px_ONE_SHOT_FIELD                        1
+#define STV090x_OFFST_Px_I2C_MODE_FIELD                        2
+#define STV090x_WIDTH_Px_I2C_MODE_FIELD                        2
+
+#define STV090x_Px_FSPYDATA(__x)                       (0xF5A2 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYDATA                            STV090x_Px_FSPYDATA(1)
+#define STV090x_P2_FSPYDATA                            STV090x_Px_FSPYDATA(2)
+#define STV090x_OFFST_Px_SPY_STUFFING_FIELD            7
+#define STV090x_WIDTH_Px_SPY_STUFFING_FIELD            1
+#define STV090x_OFFST_Px_SPY_CNULLPKT_FIELD            5
+#define STV090x_WIDTH_Px_SPY_CNULLPKT_FIELD            1
+#define STV090x_OFFST_Px_SPY_OUTDATA_MODE_FIELD                0
+#define STV090x_WIDTH_Px_SPY_OUTDATA_MODE_FIELD                5
+
+#define STV090x_Px_FSPYOUT(__x)                                (0xF5A3 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYOUT                             STV090x_Px_FSPYOUT(1)
+#define STV090x_P2_FSPYOUT                             STV090x_Px_FSPYOUT(2)
+#define STV090x_OFFST_Px_FSPY_DIRECT_FIELD             7
+#define STV090x_WIDTH_Px_FSPY_DIRECT_FIELD             1
+#define STV090x_OFFST_Px_STUFF_MODE_FIELD              0
+#define STV090x_WIDTH_Px_STUFF_MODE_FIELD              3
+
+#define STV090x_Px_FSTATUS(__x)                                (0xF5A4 - (__x - 1) * 0x200)
+#define STV090x_P1_FSTATUS                             STV090x_Px_FSTATUS(1)
+#define STV090x_P2_FSTATUS                             STV090x_Px_FSTATUS(2)
+#define STV090x_OFFST_Px_SPY_ENDSIM_FIELD              7
+#define STV090x_WIDTH_Px_SPY_ENDSIM_FIELD              1
+#define STV090x_OFFST_Px_VALID_SIM_FIELD               6
+#define STV090x_WIDTH_Px_VALID_SIM_FIELD               1
+#define STV090x_OFFST_Px_FOUND_SIGNAL_FIELD            5
+#define STV090x_WIDTH_Px_FOUND_SIGNAL_FIELD            1
+#define STV090x_OFFST_Px_DSS_SYNCBYTE_FIELD            4
+#define STV090x_WIDTH_Px_DSS_SYNCBYTE_FIELD            1
+#define STV090x_OFFST_Px_RESULT_STATE_FIELD            0
+#define STV090x_WIDTH_Px_RESULT_STATE_FIELD            4
+
+#define STV090x_Px_FBERCPT4(__x)                       (0xF5A8 - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT4                            STV090x_Px_FBERCPT4(1)
+#define STV090x_P2_FBERCPT4                            STV090x_Px_FBERCPT4(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERCPT3(__x)                       (0xF5A9 - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT3                            STV090x_Px_FBERCPT3(1)
+#define STV090x_P2_FBERCPT3                            STV090x_Px_FBERCPT3(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERCPT2(__x)                       (0xF5AA - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT2                            STV090x_Px_FBERCPT2(1)
+#define STV090x_P2_FBERCPT2                            STV090x_Px_FBERCPT2(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERCPT1(__x)                       (0xF5AB - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT1                            STV090x_Px_FBERCPT1(1)
+#define STV090x_P2_FBERCPT1                            STV090x_Px_FBERCPT1(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERCPT0(__x)                       (0xF5AC - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT0                            STV090x_Px_FBERCPT0(1)
+#define STV090x_P2_FBERCPT0                            STV090x_Px_FBERCPT0(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERERRy(__x, __y)                  (0xF5AF - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_FBERERR0                            STV090x_Px_FBERERRy(1, 0)
+#define STV090x_P1_FBERERR1                            STV090x_Px_FBERERRy(1, 1)
+#define STV090x_P1_FBERERR2                            STV090x_Px_FBERERRy(1, 2)
+#define STV090x_P2_FBERERR0                            STV090x_Px_FBERERRy(2, 0)
+#define STV090x_P2_FBERERR1                            STV090x_Px_FBERERRy(2, 1)
+#define STV090x_P2_FBERERR2                            STV090x_Px_FBERERRy(2, 2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_ERR_FIELD       0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_ERR_FIELD       8
+
+#define STV090x_Px_FSPYBER(__x)                                (0xF5B2 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYBER                             STV090x_Px_FSPYBER(1)
+#define STV090x_P2_FSPYBER                             STV090x_Px_FSPYBER(2)
+#define STV090x_OFFST_Px_FSPYBER_SYNCBYTE_FIELD                4
+#define STV090x_WIDTH_Px_FSPYBER_SYNCBYTE_FIELD                1
+#define STV090x_OFFST_Px_FSPYBER_UNSYNC_FIELD          3
+#define STV090x_WIDTH_Px_FSPYBER_UNSYNC_FIELD          1
+#define STV090x_OFFST_Px_FSPYBER_CTIME_FIELD           0
+#define STV090x_WIDTH_Px_FSPYBER_CTIME_FIELD           3
+
+#define STV090x_RCCFGH                                 0xf600
+
+#define STV090x_TSGENERAL                              0xF630
+#define STV090x_OFFST_Px_MUXSTREAM_OUT_FIELD           3
+#define STV090x_WIDTH_Px_MUXSTREAM_OUT_FIELD           1
+#define STV090x_OFFST_Px_TSFIFO_PERMPARAL_FIELD                1
+#define STV090x_WIDTH_Px_TSFIFO_PERMPARAL_FIELD                2
+
+#define STV090x_TSGENERAL1X                            0xf670
+#define STV090x_CFGEXT                                 0xfa80
+
+#define STV090x_TSTRES0                                        0xFF11
+#define STV090x_OFFST_FRESFEC_FIELD                    7
+#define STV090x_WIDTH_FRESFEC_FIELD                    1
+
+#define STV090x_Px_TSTDISRX(__x)                       (0xFF67 - (__x - 1) * 0x2)
+#define STV090x_P1_TSTDISRX                            STV090x_Px_TSTDISRX(1)
+#define STV090x_P2_TSTDISRX                            STV090x_Px_TSTDISRX(2)
+#define STV090x_OFFST_Px_TSTDISRX_SELECT_FIELD         3
+#define STV090x_WIDTH_Px_TSTDISRX_SELECT_FIELD         1
+
+#endif /* __STV090x_REG_H */
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c
new file mode 100644 (file)
index 0000000..3d8a2e0
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+       STV6110(A) Silicon tuner driver
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include "dvb_frontend.h"
+
+#include "stv6110x_reg.h"
+#include "stv6110x.h"
+#include "stv6110x_priv.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+static u8 stv6110x_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
+
+static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
+{
+       int ret;
+       const struct stv6110x_config *config = stv6110x->config;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
+               { .addr = config->addr, .flags = 0,        .buf = b0, .len = 1 },
+               { .addr = config->addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+       };
+
+       ret = i2c_transfer(stv6110x->i2c, msg, 2);
+       if (ret != 2) {
+               dprintk(FE_ERROR, 1, "I/O Error");
+               return -EREMOTEIO;
+       }
+       *data = b1[0];
+
+       return 0;
+}
+
+static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
+{
+       int ret;
+       const struct stv6110x_config *config = stv6110x->config;
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = { .addr = config->addr, .flags = 0, . buf = buf, .len = 2 };
+
+       ret = i2c_transfer(stv6110x->i2c, &msg, 1);
+       if (ret != 1) {
+               dprintk(FE_ERROR, 1, "I/O Error");
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int stv6110x_init(struct dvb_frontend *fe)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+       int ret;
+       u8 i;
+
+       for (i = 0; i < ARRAY_SIZE(stv6110x_regs); i++) {
+               ret = stv6110x_write_reg(stv6110x, i, stv6110x_regs[i]);
+               if (ret < 0) {
+                       dprintk(FE_ERROR, 1, "Initialization failed");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+       u32 rDiv, divider;
+       s32 pVal, pCalc, rDivOpt = 0;
+       u8 i;
+
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
+
+       if (frequency <= 1023000) {
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+               pVal = 40;
+       } else if (frequency <= 1300000) {
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+               pVal = 40;
+       } else if (frequency <= 2046000) {
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+               pVal = 20;
+       } else {
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+               pVal = 20;
+       }
+
+       for (rDiv = 0; rDiv <= 3; rDiv++) {
+               pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv);
+
+               if ((abs((s32)(pCalc - pVal))) < (abs((s32)(1000 - pVal))))
+                       rDivOpt = rDiv;
+       }
+
+       divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
+       divider = (divider + 5) / 10;
+
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
+
+       /* VCO Auto calibration */
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
+
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
+       stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x_regs[STV6110x_TNG1]);
+       stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x_regs[STV6110x_TNG0]);
+       stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+
+       for (i = 0; i < TRIALS; i++) {
+               stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+               if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x_regs[STV6110x_STAT1]))
+                               break;
+               msleep(1);
+       }
+
+       return 0;
+}
+
+static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x_regs[STV6110x_TNG1]);
+       stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x_regs[STV6110x_TNG0]);
+
+       *frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x_regs[STV6110x_TNG1]),
+                                STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x_regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
+
+       *frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x_regs[STV6110x_TNG1]) +
+                            STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x_regs[STV6110x_TNG1])));
+
+       *frequency >>= 2;
+
+       return 0;
+}
+
+static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+       u32 halfbw;
+       u8 i;
+
+       halfbw = bandwidth >> 1;
+
+       if (halfbw > 36000000)
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
+       else if (halfbw < 5000000)
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
+       else
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
+
+
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
+
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
+       stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+
+       for (i = 0; i < TRIALS; i++) {
+               stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+               if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x_regs[STV6110x_STAT1]))
+                       break;
+               msleep(1);
+       }
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
+
+       return 0;
+}
+
+static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x_regs[STV6110x_CTRL3]);
+       *bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x_regs[STV6110x_CTRL3]) + 5) * 2000000;
+
+       return 0;
+}
+
+static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       /* setup divider */
+       switch (refclock) {
+       default:
+       case 1:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
+               break;
+       case 2:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
+               break;
+       case 4:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
+               break;
+       case 8:
+       case 0:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
+               break;
+       }
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+
+       return 0;
+}
+
+static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x_regs[STV6110x_CTRL2]);
+       *gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x_regs[STV6110x_CTRL2]);
+
+       return 0;
+}
+
+static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+
+       return 0;
+}
+
+static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+       int ret;
+
+       switch (mode) {
+       case TUNER_SLEEP:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 0);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 0);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 0);
+               break;
+
+       case TUNER_WAKE:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 1);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 1);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 1);
+               break;
+       }
+
+       ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
+       if (ret < 0) {
+               dprintk(FE_ERROR, 1, "I/O Error");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int stv6110x_sleep(struct dvb_frontend *fe)
+{
+       return stv6110x_set_mode(fe, TUNER_SLEEP);
+}
+
+static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+
+       if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x_regs[STV6110x_STAT1]))
+               *status = TUNER_PHASELOCKED;
+       else
+               *status = 0;
+
+       return 0;
+}
+
+
+static int stv6110x_release(struct dvb_frontend *fe)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       fe->tuner_priv = NULL;
+       kfree(stv6110x);
+
+       return 0;
+}
+
+static struct dvb_tuner_ops stv6110x_ops = {
+       .info = {
+               .name           = "STV6110(A) Silicon Tuner",
+               .frequency_min  =  950000,
+               .frequency_max  = 2150000,
+               .frequency_step = 0,
+       },
+
+       .init                   = stv6110x_init,
+       .sleep                  = stv6110x_sleep,
+       .release                = stv6110x_release
+};
+
+static struct stv6110x_devctl stv6110x_ctl = {
+       .tuner_init             = stv6110x_init,
+       .tuner_set_mode         = stv6110x_set_mode,
+       .tuner_set_frequency    = stv6110x_set_frequency,
+       .tuner_get_frequency    = stv6110x_get_frequency,
+       .tuner_set_bandwidth    = stv6110x_set_bandwidth,
+       .tuner_get_bandwidth    = stv6110x_get_bandwidth,
+       .tuner_set_bbgain       = stv6110x_set_bbgain,
+       .tuner_get_bbgain       = stv6110x_get_bbgain,
+       .tuner_set_refclk       = stv6110x_set_refclock,
+       .tuner_get_status       = stv6110x_get_status,
+};
+
+struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+                                       const struct stv6110x_config *config,
+                                       struct i2c_adapter *i2c)
+{
+       struct stv6110x_state *stv6110x;
+
+       stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
+       if (stv6110x == NULL)
+               goto error;
+
+       stv6110x->i2c           = i2c;
+       stv6110x->config        = config;
+       stv6110x->devctl        = &stv6110x_ctl;
+
+       fe->tuner_priv          = stv6110x;
+       fe->ops.tuner_ops       = stv6110x_ops;
+
+       printk("%s: Attaching STV6110x \n", __func__);
+       return stv6110x->devctl;
+
+error:
+       kfree(stv6110x);
+       return NULL;
+}
+EXPORT_SYMBOL(stv6110x_attach);
+
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STV6110x Silicon tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv6110x.h b/drivers/media/dvb/frontends/stv6110x.h
new file mode 100644 (file)
index 0000000..a382570
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+       STV6110(A) Silicon tuner driver
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV6110x_H
+#define __STV6110x_H
+
+struct stv6110x_config {
+       u8      addr;
+       u32     refclk;
+};
+
+enum tuner_mode {
+       TUNER_SLEEP = 1,
+       TUNER_WAKE,
+};
+
+enum tuner_status {
+       TUNER_PHASELOCKED = 1,
+};
+
+struct stv6110x_devctl {
+       int (*tuner_init) (struct dvb_frontend *fe);
+       int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
+       int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
+       int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
+       int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
+       int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
+       int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
+       int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
+       int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
+       int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
+};
+
+
+#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
+
+extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+                                              const struct stv6110x_config *config,
+                                              struct i2c_adapter *i2c);
+
+#else
+static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+                                                     const struct stv6110x_config *config,
+                                                     struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif /* CONFIG_DVB_STV6110x */
+
+#endif /* __STV6110x_H */
diff --git a/drivers/media/dvb/frontends/stv6110x_priv.h b/drivers/media/dvb/frontends/stv6110x_priv.h
new file mode 100644 (file)
index 0000000..7260da6
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+       STV6110(A) Silicon tuner driver
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV6110x_PRIV_H
+#define __STV6110x_PRIV_H
+
+#define FE_ERROR                               0
+#define FE_NOTICE                              1
+#define FE_INFO                                        2
+#define FE_DEBUG                               3
+#define FE_DEBUGREG                            4
+
+#define dprintk(__y, __z, format, arg...) do {                                         \
+       if (__z) {                                                                      \
+               if      ((verbose > FE_ERROR) && (verbose > __y))                       \
+                       printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);          \
+               else if ((verbose > FE_NOTICE) && (verbose > __y))                      \
+                       printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);       \
+               else if ((verbose > FE_INFO) && (verbose > __y))                        \
+                       printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);         \
+               else if ((verbose > FE_DEBUG) && (verbose > __y))                       \
+                       printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);        \
+       } else {                                                                        \
+               if (verbose > __y)                                                      \
+                       printk(format, ##arg);                                          \
+       }                                                                               \
+} while (0)
+
+
+#define STV6110x_SETFIELD(mask, bitf, val)                             \
+       (mask = (mask & (~(((1 << STV6110x_WIDTH_##bitf) - 1) <<        \
+                                 STV6110x_OFFST_##bitf))) |            \
+                         (val << STV6110x_OFFST_##bitf))
+
+#define STV6110x_GETFIELD(bitf, val)                                   \
+       ((val >> STV6110x_OFFST_##bitf) &                               \
+       ((1 << STV6110x_WIDTH_##bitf) - 1))
+
+#define MAKEWORD16(a, b)                       (((a) << 8) | (b))
+
+#define LSB(x)                                 ((x & 0xff))
+#define MSB(y)                                 ((y >> 8) & 0xff)
+
+#define TRIALS                                 10
+#define R_DIV(__div)                           (1 << (__div + 1))
+#define REFCLOCK_kHz                           (stv6110x->config->refclk /    1000)
+#define REFCLOCK_MHz                           (stv6110x->config->refclk / 1000000)
+
+struct stv6110x_state {
+       struct i2c_adapter              *i2c;
+       const struct stv6110x_config    *config;
+
+       struct stv6110x_devctl          *devctl;
+};
+
+#endif /* __STV6110x_PRIV_H */
diff --git a/drivers/media/dvb/frontends/stv6110x_reg.h b/drivers/media/dvb/frontends/stv6110x_reg.h
new file mode 100644 (file)
index 0000000..93e5c70
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+       STV6110(A) Silicon tuner driver
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV6110x_REG_H
+#define __STV6110x_REG_H
+
+#define STV6110x_CTRL1                         0x00
+#define STV6110x_OFFST_CTRL1_K                 3
+#define STV6110x_WIDTH_CTRL1_K                 5
+#define STV6110x_OFFST_CTRL1_LPT               2
+#define STV6110x_WIDTH_CTRL1_LPT               1
+#define STV6110x_OFFST_CTRL1_RX                        1
+#define STV6110x_WIDTH_CTRL1_RX                        1
+#define STV6110x_OFFST_CTRL1_SYN               0
+#define STV6110x_WIDTH_CTRL1_SYN               1
+
+#define STV6110x_CTRL2                         0x01
+#define STV6110x_OFFST_CTRL2_CO_DIV            6
+#define STV6110x_WIDTH_CTRL2_CO_DIV            2
+#define STV6110x_OFFST_CTRL2_RSVD              5
+#define STV6110x_WIDTH_CTRL2_RSVD              1
+#define STV6110x_OFFST_CTRL2_REFOUT_SEL                4
+#define STV6110x_WIDTH_CTRL2_REFOUT_SEL                1
+#define STV6110x_OFFST_CTRL2_BBGAIN            0
+#define STV6110x_WIDTH_CTRL2_BBGAIN            4
+
+#define STV6110x_TNG0                          0x02
+#define STV6110x_OFFST_TNG0_N_DIV_7_0          0
+#define STV6110x_WIDTH_TNG0_N_DIV_7_0          8
+
+#define STV6110x_TNG1                          0x03
+#define STV6110x_OFFST_TNG1_R_DIV              6
+#define STV6110x_WIDTH_TNG1_R_DIV              2
+#define STV6110x_OFFST_TNG1_PRESC32_ON         5
+#define STV6110x_WIDTH_TNG1_PRESC32_ON         1
+#define STV6110x_OFFST_TNG1_DIV4SEL            4
+#define STV6110x_WIDTH_TNG1_DIV4SEL            1
+#define STV6110x_OFFST_TNG1_N_DIV_11_8         0
+#define STV6110x_WIDTH_TNG1_N_DIV_11_8         4
+
+
+#define STV6110x_CTRL3                         0x04
+#define STV6110x_OFFST_CTRL3_DCLOOP_OFF                7
+#define STV6110x_WIDTH_CTRL3_DCLOOP_OFF                1
+#define STV6110x_OFFST_CTRL3_RCCLK_OFF         6
+#define STV6110x_WIDTH_CTRL3_RCCLK_OFF         1
+#define STV6110x_OFFST_CTRL3_ICP               5
+#define STV6110x_WIDTH_CTRL3_ICP               1
+#define STV6110x_OFFST_CTRL3_CF                        0
+#define STV6110x_WIDTH_CTRL3_CF                        5
+
+#define STV6110x_STAT1                         0x05
+#define STV6110x_OFFST_STAT1_CALVCO_STRT       2
+#define STV6110x_WIDTH_STAT1_CALVCO_STRT       1
+#define STV6110x_OFFST_STAT1_CALRC_STRT                1
+#define STV6110x_WIDTH_STAT1_CALRC_STRT                1
+#define STV6110x_OFFST_STAT1_LOCK              0
+#define STV6110x_WIDTH_STAT1_LOCK              1
+
+#define STV6110x_STAT2                         0x06
+#define STV6110x_STAT3                         0x07
+
+#endif /* __STV6110x_REG_H */
index 2a8bbcd44cd02a40f86921eac66bcf5455076391..4302c563a6b8950f6bdf045ee55a8adbbf2ea7e7 100644 (file)
@@ -1,7 +1,7 @@
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2009 Steven Toth <stoth@kernellabs.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
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <asm/div64.h>
 #include "dvb_frontend.h"
 #include "dvb_math.h"
 #include "tda10048.h"
@@ -138,11 +139,20 @@ struct tda10048_state {
 
        struct i2c_adapter *i2c;
 
-       /* configuration settings */
-       const struct tda10048_config *config;
+       /* We'll cache and update the attach config settings */
+       struct tda10048_config config;
        struct dvb_frontend frontend;
 
        int fwloaded;
+
+       u32 freq_if_hz;
+       u32 xtal_hz;
+       u32 pll_mfactor;
+       u32 pll_nfactor;
+       u32 pll_pfactor;
+       u32 sample_freq;
+
+       enum fe_bandwidth bandwidth;
 };
 
 static struct init_tab {
@@ -192,12 +202,26 @@ static struct init_tab {
        { TDA10048_CONF_C4_2, 0x04 },
 };
 
+static struct pll_tab {
+       u32     clk_freq_khz;
+       u32     if_freq_khz;
+       u8      m, n, p;
+} pll_tab[] = {
+       { TDA10048_CLK_4000,  TDA10048_IF_36130, 10, 0, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_3300,  10, 3, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_3500,  10, 3, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_4000,  10, 3, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_4300,  10, 3, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 },
+};
+
 static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
 {
+       struct tda10048_config *config = &state->config;
        int ret;
        u8 buf[] = { reg, data };
        struct i2c_msg msg = {
-               .addr = state->config->demod_address,
+               .addr = config->demod_address,
                .flags = 0, .buf = buf, .len = 2 };
 
        dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
@@ -212,13 +236,14 @@ static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
 
 static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
 {
+       struct tda10048_config *config = &state->config;
        int ret;
        u8 b0[] = { reg };
        u8 b1[] = { 0 };
        struct i2c_msg msg[] = {
-               { .addr = state->config->demod_address,
+               { .addr = config->demod_address,
                        .flags = 0, .buf = b0, .len = 1 },
-               { .addr = state->config->demod_address,
+               { .addr = config->demod_address,
                        .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 
        dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
@@ -235,6 +260,7 @@ static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
 static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
                                 const u8 *data, u16 len)
 {
+       struct tda10048_config *config = &state->config;
        int ret = -EREMOTEIO;
        struct i2c_msg msg;
        u8 *buf;
@@ -250,7 +276,7 @@ static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
        *buf = reg;
        memcpy(buf + 1, data, len);
 
-       msg.addr = state->config->demod_address;
+       msg.addr = config->demod_address;
        msg.flags = 0;
        msg.buf = buf;
        msg.len = len + 1;
@@ -271,14 +297,206 @@ error:
        return ret;
 }
 
+static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz,
+                            u32 if_hz)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       u64 t;
+
+       dprintk(1, "%s()\n", __func__);
+
+       if (sample_freq_hz == 0)
+               return -EINVAL;
+
+       if (if_hz < (sample_freq_hz / 2)) {
+               /* PHY2 = (if2/fs) * 2^15 */
+               t = if_hz;
+               t *= 10;
+               t *= 32768;
+               do_div(t, sample_freq_hz);
+               t += 5;
+               do_div(t, 10);
+       } else {
+               /* PHY2 = ((IF1-fs)/fs) * 2^15 */
+               t = sample_freq_hz - if_hz;
+               t *= 10;
+               t *= 32768;
+               do_div(t, sample_freq_hz);
+               t += 5;
+               do_div(t, 10);
+               t = ~t + 1;
+       }
+
+       tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t);
+       tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8));
+
+       return 0;
+}
+
+static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz,
+                            u32 bw)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       u64 t, z;
+       u32 b = 8000000;
+
+       dprintk(1, "%s()\n", __func__);
+
+       if (sample_freq_hz == 0)
+               return -EINVAL;
+
+       if (bw == BANDWIDTH_6_MHZ)
+               b = 6000000;
+       else
+       if (bw == BANDWIDTH_7_MHZ)
+               b = 7000000;
+
+       /* WREF = (B / (7 * fs)) * 2^31 */
+       t = b * 10;
+       /* avoid warning: this decimal constant is unsigned only in ISO C90 */
+       /* t *= 2147483648 on 32bit platforms */
+       t *= (2048 * 1024);
+       t *= 1024;
+       z = 7 * sample_freq_hz;
+       do_div(t, z);
+       t += 5;
+       do_div(t, 10);
+
+       tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t);
+       tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8));
+       tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16));
+       tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24));
+
+       return 0;
+}
+
+static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
+                               u32 bw)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       u64 t;
+       u32 b = 8000000;
+
+       dprintk(1, "%s()\n", __func__);
+
+       if (sample_freq_hz == 0)
+               return -EINVAL;
+
+       if (bw == BANDWIDTH_6_MHZ)
+               b = 6000000;
+       else
+       if (bw == BANDWIDTH_7_MHZ)
+               b = 7000000;
+
+       /* INVWREF = ((7 * fs) / B) * 2^5 */
+       t = sample_freq_hz;
+       t *= 7;
+       t *= 32;
+       t *= 10;
+       do_div(t, b);
+       t += 5;
+       do_div(t, 10);
+
+       tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t);
+       tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8));
+
+       return 0;
+}
+
+static int tda10048_set_bandwidth(struct dvb_frontend *fe,
+       enum fe_bandwidth bw)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       dprintk(1, "%s(bw=%d)\n", __func__, bw);
+
+       /* Bandwidth setting may need to be adjusted */
+       switch (bw) {
+       case BANDWIDTH_6_MHZ:
+       case BANDWIDTH_7_MHZ:
+       case BANDWIDTH_8_MHZ:
+               tda10048_set_wref(fe, state->sample_freq, bw);
+               tda10048_set_invwref(fe, state->sample_freq, bw);
+               break;
+       default:
+               printk(KERN_ERR "%s() invalid bandwidth\n", __func__);
+               return -EINVAL;
+       }
+
+       state->bandwidth = bw;
+
+       return 0;
+}
+
+static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
+       int i;
+       u32 if_freq_khz;
+
+       dprintk(1, "%s(bw = %d)\n", __func__, bw);
+
+       /* based on target bandwidth and clk we calculate pll factors */
+       switch (bw) {
+       case BANDWIDTH_6_MHZ:
+               if_freq_khz = config->dtv6_if_freq_khz;
+               break;
+       case BANDWIDTH_7_MHZ:
+               if_freq_khz = config->dtv7_if_freq_khz;
+               break;
+       case BANDWIDTH_8_MHZ:
+               if_freq_khz = config->dtv8_if_freq_khz;
+               break;
+       default:
+               printk(KERN_ERR "%s() no default\n", __func__);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(pll_tab); i++) {
+               if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) &&
+                       (pll_tab[i].if_freq_khz == if_freq_khz)) {
+
+                       state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
+                       state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
+                       state->pll_mfactor = pll_tab[i].m;
+                       state->pll_nfactor = pll_tab[i].n;
+                       state->pll_pfactor = pll_tab[i].p;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(pll_tab)) {
+               printk(KERN_ERR "%s() Incorrect attach settings\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz);
+       dprintk(1, "- xtal_hz = %d\n", state->xtal_hz);
+       dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor);
+       dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor);
+       dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);
+
+       /* Calculate the sample frequency */
+       state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45);
+       state->sample_freq /= (state->pll_nfactor + 1);
+       state->sample_freq /= (state->pll_pfactor + 4);
+       dprintk(1, "- sample_freq = %d\n", state->sample_freq);
+
+       /* Update the I/F */
+       tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz);
+
+       return 0;
+}
+
 static int tda10048_firmware_upload(struct dvb_frontend *fe)
 {
        struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
        const struct firmware *fw;
        int ret;
        int pos = 0;
        int cnt;
-       u8 wlen = state->config->fwbulkwritelen;
+       u8 wlen = config->fwbulkwritelen;
 
        if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
                wlen = TDA10048_BULKWRITE_200;
@@ -289,7 +507,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe)
                TDA10048_DEFAULT_FIRMWARE);
 
        ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
-               &state->i2c->dev);
+               state->i2c->dev.parent);
        if (ret) {
                printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
                        __func__);
@@ -484,8 +702,12 @@ static int tda10048_get_tps(struct tda10048_state *state,
 static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
        dprintk(1, "%s(%d)\n", __func__, enable);
 
+       if (config->disable_gate_access)
+               return 0;
+
        if (enable)
                return tda10048_writereg(state, TDA10048_CONF_C4_1,
                        tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
@@ -523,6 +745,12 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
 
        dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
 
+       /* Update the I/F pll's if the bandwidth changes */
+       if (p->u.ofdm.bandwidth != state->bandwidth) {
+               tda10048_set_if(fe, p->u.ofdm.bandwidth);
+               tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth);
+       }
+
        if (fe->ops.tuner_ops.set_params) {
 
                if (fe->ops.i2c_gate_ctrl)
@@ -544,6 +772,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
 static int tda10048_init(struct dvb_frontend *fe)
 {
        struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
        int ret = 0, i;
 
        dprintk(1, "%s()\n", __func__);
@@ -556,10 +785,14 @@ static int tda10048_init(struct dvb_frontend *fe)
                ret = tda10048_firmware_upload(fe);
 
        /* Set either serial or parallel */
-       tda10048_output_mode(fe, state->config->output_mode);
+       tda10048_output_mode(fe, config->output_mode);
+
+       /* Set inversion */
+       tda10048_set_inversion(fe, config->inversion);
 
-       /* set inversion */
-       tda10048_set_inversion(fe, state->config->inversion);
+       /* Establish default RF values */
+       tda10048_set_if(fe, BANDWIDTH_8_MHZ);
+       tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ);
 
        /* Ensure we leave the gate closed */
        tda10048_i2c_gate_ctrl(fe, 0);
@@ -812,6 +1045,45 @@ static void tda10048_release(struct dvb_frontend *fe)
        kfree(state);
 }
 
+static void tda10048_establish_defaults(struct dvb_frontend *fe)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
+
+       /* Validate/default the config */
+       if (config->dtv6_if_freq_khz == 0) {
+               config->dtv6_if_freq_khz = TDA10048_IF_4300;
+               printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz "
+                       "is not set (defaulting to %d)\n",
+                       __func__,
+                       config->dtv6_if_freq_khz);
+       }
+
+       if (config->dtv7_if_freq_khz == 0) {
+               config->dtv7_if_freq_khz = TDA10048_IF_4300;
+               printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz "
+                       "is not set (defaulting to %d)\n",
+                       __func__,
+                       config->dtv7_if_freq_khz);
+       }
+
+       if (config->dtv8_if_freq_khz == 0) {
+               config->dtv8_if_freq_khz = TDA10048_IF_4300;
+               printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz "
+                       "is not set (defaulting to %d)\n",
+                       __func__,
+                       config->dtv8_if_freq_khz);
+       }
+
+       if (config->clk_freq_khz == 0) {
+               config->clk_freq_khz = TDA10048_CLK_16000;
+               printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz "
+                       "is not set (defaulting to %d)\n",
+                       __func__,
+                       config->clk_freq_khz);
+       }
+}
+
 static struct dvb_frontend_ops tda10048_ops;
 
 struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
@@ -826,10 +1098,11 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
        if (state == NULL)
                goto error;
 
-       /* setup the state */
-       state->config = config;
+       /* setup the state and clone the config */
+       memcpy(&state->config, config, sizeof(*config));
        state->i2c = i2c;
        state->fwloaded = 0;
+       state->bandwidth = BANDWIDTH_8_MHZ;
 
        /* check if the demod is present */
        if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
@@ -840,6 +1113,17 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
                sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
+       /* Establish any defaults the the user didn't pass */
+       tda10048_establish_defaults(&state->frontend);
+
+       /* Set the xtal and freq defaults */
+       if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+               goto error;
+
+       /* Default bandwidth */
+       if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+               goto error;
+
        /* Leave the gate closed */
        tda10048_i2c_gate_ctrl(&state->frontend, 0);
 
index 0457b24601fa1239d34935811bbe165bf47428d3..8828ceaf74bb491dad21c12759d0a1b316ec8a0c 100644 (file)
@@ -1,7 +1,7 @@
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2009 Steven Toth <stoth@kernellabs.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
@@ -43,6 +43,25 @@ struct tda10048_config {
 #define TDA10048_INVERSION_OFF 0
 #define TDA10048_INVERSION_ON  1
        u8 inversion;
+
+#define TDA10048_IF_3300  3300
+#define TDA10048_IF_3500  3500
+#define TDA10048_IF_3800  3800
+#define TDA10048_IF_4000  4000
+#define TDA10048_IF_4300  4300
+#define TDA10048_IF_4500  4500
+#define TDA10048_IF_4750  4750
+#define TDA10048_IF_36130 36130
+       u16 dtv6_if_freq_khz;
+       u16 dtv7_if_freq_khz;
+       u16 dtv8_if_freq_khz;
+
+#define TDA10048_CLK_4000  4000
+#define TDA10048_CLK_16000 16000
+       u16 clk_freq_khz;
+
+       /* Disable I2C gate access */
+       u8 disable_gate_access;
 };
 
 #if defined(CONFIG_DVB_TDA10048) || \
index bcf93f4828b28cbc7dace4c0b27d1bcc27db62e3..c6644d9094338ef252c2ca98ae4fd179199c67d7 100644 (file)
@@ -1,4 +1,4 @@
-sms1xxx-objs := smscoreapi.o sms-cards.o
+sms1xxx-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
 
 obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
 obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o
index 63e4d0ec6583e95010ab8db2a5e853a1b81c79fb..d8b15d583bdeb2e662a3d336aabd7017d2414722 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include "sms-cards.h"
+#include "smsir.h"
 
 static int sms_dbg;
 module_param_named(cards_dbg, sms_dbg, int, 0644);
@@ -30,17 +31,14 @@ static struct sms_board sms_boards[] = {
        [SMS1XXX_BOARD_SIANO_STELLAR] = {
                .name   = "Siano Stellar Digital Receiver",
                .type   = SMS_STELLAR,
-               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
        },
        [SMS1XXX_BOARD_SIANO_NOVA_A] = {
                .name   = "Siano Nova A Digital Receiver",
                .type   = SMS_NOVA_A0,
-               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
        },
        [SMS1XXX_BOARD_SIANO_NOVA_B] = {
                .name   = "Siano Nova B Digital Receiver",
                .type   = SMS_NOVA_B0,
-               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
        },
        [SMS1XXX_BOARD_SIANO_VEGA] = {
                .name   = "Siano Vega Digital Receiver",
@@ -65,6 +63,9 @@ static struct sms_board sms_boards[] = {
                .name   = "Hauppauge WinTV MiniStick",
                .type   = SMS_NOVA_B0,
                .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+               .board_cfg.leds_power = 26,
+               .board_cfg.led0 = 27,
+               .board_cfg.led1 = 28,
                .led_power = 26,
                .led_lo    = 27,
                .led_hi    = 28,
@@ -74,7 +75,9 @@ static struct sms_board sms_boards[] = {
                .type   = SMS_NOVA_B0,
                .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
                .lna_ctrl  = 29,
+               .board_cfg.foreign_lna0_ctrl = 29,
                .rf_switch = 17,
+               .board_cfg.rf_switch_uhf = 17,
        },
        [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
                .name   = "Hauppauge WinTV MiniCard",
@@ -82,6 +85,16 @@ static struct sms_board sms_boards[] = {
                .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
                .lna_ctrl  = -1,
        },
+       [SMS1XXX_BOARD_SIANO_NICE] = {
+       /* 11 */
+               .name = "Siano Nice Digital Receiver",
+               .type = SMS_NOVA_B0,
+       },
+       [SMS1XXX_BOARD_SIANO_VENICE] = {
+       /* 12 */
+               .name = "Siano Venice Digital Receiver",
+               .type = SMS_VEGA,
+       },
 };
 
 struct sms_board *sms_get_board(int id)
@@ -91,12 +104,179 @@ struct sms_board *sms_get_board(int id)
        return &sms_boards[id];
 }
 EXPORT_SYMBOL_GPL(sms_get_board);
+static inline void sms_gpio_assign_11xx_default_led_config(
+               struct smscore_gpio_config *pGpioConfig) {
+       pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
+       pGpioConfig->InputCharacteristics =
+               SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
+       pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
+       pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
+       pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
+}
+
+int sms_board_event(struct smscore_device_t *coredev,
+               enum SMS_BOARD_EVENTS gevent) {
+       int board_id = smscore_get_board_id(coredev);
+       struct sms_board *board = sms_get_board(board_id);
+       struct smscore_gpio_config MyGpioConfig;
+
+       sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
+
+       switch (gevent) {
+       case BOARD_EVENT_POWER_INIT: /* including hotplug */
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       /* set I/O and turn off all LEDs */
+                       smscore_gpio_configure(coredev,
+                                       board->board_cfg.leds_power,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.leds_power, 0);
+                       smscore_gpio_configure(coredev, board->board_cfg.led0,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.led0, 0);
+                       smscore_gpio_configure(coredev, board->board_cfg.led1,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       /* set I/O and turn off LNA */
+                       smscore_gpio_configure(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       0);
+                       break;
+               }
+               break; /* BOARD_EVENT_BIND */
+
+       case BOARD_EVENT_POWER_SUSPEND:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.leds_power, 0);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led0, 0);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       0);
+                       break;
+               }
+               break; /* BOARD_EVENT_POWER_SUSPEND */
+
+       case BOARD_EVENT_POWER_RESUME:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.leds_power, 1);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led0, 1);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       1);
+                       break;
+               }
+               break; /* BOARD_EVENT_POWER_RESUME */
+
+       case BOARD_EVENT_BIND:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                               board->board_cfg.leds_power, 1);
+                       smscore_gpio_set_level(coredev,
+                               board->board_cfg.led0, 1);
+                       smscore_gpio_set_level(coredev,
+                               board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       1);
+                       break;
+               }
+               break; /* BOARD_EVENT_BIND */
+
+       case BOARD_EVENT_SCAN_PROG:
+               break; /* BOARD_EVENT_SCAN_PROG */
+       case BOARD_EVENT_SCAN_COMP:
+               break; /* BOARD_EVENT_SCAN_COMP */
+       case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
+               break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
+       case BOARD_EVENT_FE_LOCK:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                       board->board_cfg.led1, 1);
+                       break;
+               }
+               break; /* BOARD_EVENT_FE_LOCK */
+       case BOARD_EVENT_FE_UNLOCK:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               }
+               break; /* BOARD_EVENT_FE_UNLOCK */
+       case BOARD_EVENT_DEMOD_LOCK:
+               break; /* BOARD_EVENT_DEMOD_LOCK */
+       case BOARD_EVENT_DEMOD_UNLOCK:
+               break; /* BOARD_EVENT_DEMOD_UNLOCK */
+       case BOARD_EVENT_RECEPTION_MAX_4:
+               break; /* BOARD_EVENT_RECEPTION_MAX_4 */
+       case BOARD_EVENT_RECEPTION_3:
+               break; /* BOARD_EVENT_RECEPTION_3 */
+       case BOARD_EVENT_RECEPTION_2:
+               break; /* BOARD_EVENT_RECEPTION_2 */
+       case BOARD_EVENT_RECEPTION_1:
+               break; /* BOARD_EVENT_RECEPTION_1 */
+       case BOARD_EVENT_RECEPTION_LOST_0:
+               break; /* BOARD_EVENT_RECEPTION_LOST_0 */
+       case BOARD_EVENT_MULTIPLEX_OK:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 1);
+                       break;
+               }
+               break; /* BOARD_EVENT_MULTIPLEX_OK */
+       case BOARD_EVENT_MULTIPLEX_ERRORS:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               }
+               break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
+
+       default:
+               sms_err("Unknown SMS board event");
+               break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_event);
 
 static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
 {
        int lvl, ret;
        u32 gpio;
-       struct smscore_gpio_config gpioconfig = {
+       struct smscore_config_gpio gpioconfig = {
                .direction            = SMS_GPIO_DIRECTION_OUTPUT,
                .pullupdown           = SMS_GPIO_PULLUPDOWN_NONE,
                .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
index 64d74c59c33f9503760207f9dcf1f1a775f1ac1d..38f062f6ad68a95c462a49afeb196ad37b580b07 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/usb.h>
 #include "smscoreapi.h"
+#include "smsir.h"
 
 #define SMS_BOARD_UNKNOWN 0
 #define SMS1XXX_BOARD_SIANO_STELLAR 1
 #define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
+#define SMS1XXX_BOARD_SIANO_NICE       11
+#define SMS1XXX_BOARD_SIANO_VENICE     12
+
+struct sms_board_gpio_cfg {
+       int lna_vhf_exist;
+       int lna_vhf_ctrl;
+       int lna_uhf_exist;
+       int lna_uhf_ctrl;
+       int lna_uhf_d_ctrl;
+       int lna_sband_exist;
+       int lna_sband_ctrl;
+       int lna_sband_d_ctrl;
+       int foreign_lna0_ctrl;
+       int foreign_lna1_ctrl;
+       int foreign_lna2_ctrl;
+       int rf_switch_vhf;
+       int rf_switch_uhf;
+       int rf_switch_sband;
+       int leds_power;
+       int led0;
+       int led1;
+       int led2;
+       int led3;
+       int led4;
+       int ir;
+       int eeprom_wp;
+       int mrc_sense;
+       int mrc_pdn_resetn;
+       int mrc_gp0; /* mrcs spi int */
+       int mrc_gp1;
+       int mrc_gp2;
+       int mrc_gp3;
+       int mrc_gp4;
+       int host_spi_gsp_ts_int;
+};
 
 struct sms_board {
        enum sms_device_type_st type;
        char *name, *fw[DEVICE_MODE_MAX];
+       struct sms_board_gpio_cfg board_cfg;
+       enum ir_kb_type ir_kb_type;
 
        /* gpios */
        int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
@@ -45,6 +83,32 @@ struct sms_board {
 
 struct sms_board *sms_get_board(int id);
 
+extern struct smscore_device_t *coredev;
+
+enum SMS_BOARD_EVENTS {
+       BOARD_EVENT_POWER_INIT,
+       BOARD_EVENT_POWER_SUSPEND,
+       BOARD_EVENT_POWER_RESUME,
+       BOARD_EVENT_BIND,
+       BOARD_EVENT_SCAN_PROG,
+       BOARD_EVENT_SCAN_COMP,
+       BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
+       BOARD_EVENT_FE_LOCK,
+       BOARD_EVENT_FE_UNLOCK,
+       BOARD_EVENT_DEMOD_LOCK,
+       BOARD_EVENT_DEMOD_UNLOCK,
+       BOARD_EVENT_RECEPTION_MAX_4,
+       BOARD_EVENT_RECEPTION_3,
+       BOARD_EVENT_RECEPTION_2,
+       BOARD_EVENT_RECEPTION_1,
+       BOARD_EVENT_RECEPTION_LOST_0,
+       BOARD_EVENT_MULTIPLEX_OK,
+       BOARD_EVENT_MULTIPLEX_ERRORS
+};
+
+int sms_board_event(struct smscore_device_t *coredev,
+               enum SMS_BOARD_EVENTS gevent);
+
 int sms_board_setup(struct smscore_device_t *coredev);
 
 #define SMS_LED_OFF 0
index 7bd4d1dee2b32022bf52ff5923b95f423bd81e45..32be382f0e97717f7c2f7c95c40f689374f4a994 100644 (file)
 #include <linux/io.h>
 
 #include <linux/firmware.h>
+#include <linux/wait.h>
+#include <asm/byteorder.h>
 
 #include "smscoreapi.h"
 #include "sms-cards.h"
+#include "smsir.h"
+#include "smsendian.h"
 
 static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
@@ -58,42 +62,6 @@ struct smscore_client_t {
        onremove_t              onremove_handler;
 };
 
-struct smscore_device_t {
-       struct list_head entry;
-
-       struct list_head clients;
-       struct list_head subclients;
-       spinlock_t              clientslock;
-
-       struct list_head buffers;
-       spinlock_t              bufferslock;
-       int                             num_buffers;
-
-       void                    *common_buffer;
-       int                             common_buffer_size;
-       dma_addr_t              common_buffer_phys;
-
-       void                    *context;
-       struct device   *device;
-
-       char                    devpath[32];
-       unsigned long   device_flags;
-
-       setmode_t               setmode_handler;
-       detectmode_t    detectmode_handler;
-       sendrequest_t   sendrequest_handler;
-       preload_t               preload_handler;
-       postload_t              postload_handler;
-
-       int                             mode, modes_supported;
-
-       struct completion version_ex_done, data_download_done, trigger_done;
-       struct completion init_device_done, reload_start_done, resume_done;
-
-       int board_id;
-       int led_state;
-};
-
 void smscore_set_board_id(struct smscore_device_t *core, int id)
 {
        core->board_id = id;
@@ -384,6 +352,13 @@ int smscore_register_device(struct smsdevice_params_t *params,
        init_completion(&dev->init_device_done);
        init_completion(&dev->reload_start_done);
        init_completion(&dev->resume_done);
+       init_completion(&dev->gpio_configuration_done);
+       init_completion(&dev->gpio_set_level_done);
+       init_completion(&dev->gpio_get_level_done);
+       init_completion(&dev->ir_init_done);
+
+       /* Buffer management */
+       init_waitqueue_head(&dev->buffer_mng_waitq);
 
        /* alloc common buffer */
        dev->common_buffer_size = params->buffer_size * params->num_buffers;
@@ -439,6 +414,71 @@ int smscore_register_device(struct smsdevice_params_t *params,
 }
 EXPORT_SYMBOL_GPL(smscore_register_device);
 
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+               void *buffer, size_t size, struct completion *completion) {
+       int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+       if (rc < 0) {
+               sms_info("sendrequest returned error %d", rc);
+               return rc;
+       }
+
+       return wait_for_completion_timeout(completion,
+                       msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
+                       0 : -ETIME;
+}
+
+/**
+ * Starts & enables IR operations
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int smscore_init_ir(struct smscore_device_t *coredev)
+{
+       int ir_io;
+       int rc;
+       void *buffer;
+
+       coredev->ir.input_dev = NULL;
+       ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
+       if (ir_io) {/* only if IR port exist we use IR sub-module */
+               sms_info("IR loading");
+               rc = sms_ir_init(coredev);
+
+               if      (rc != 0)
+                       sms_err("Error initialization DTV IR sub-module");
+               else {
+                       buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
+                                               SMS_DMA_ALIGNMENT,
+                                               GFP_KERNEL | GFP_DMA);
+                       if (buffer) {
+                               struct SmsMsgData_ST2 *msg =
+                               (struct SmsMsgData_ST2 *)
+                               SMS_ALIGN_ADDRESS(buffer);
+
+                               SMS_INIT_MSG(&msg->xMsgHeader,
+                                               MSG_SMS_START_IR_REQ,
+                                               sizeof(struct SmsMsgData_ST2));
+                               msg->msgData[0] = coredev->ir.controller;
+                               msg->msgData[1] = coredev->ir.timeout;
+
+                               smsendian_handle_tx_message(
+                                       (struct SmsMsgHdr_ST2 *)msg);
+                               rc = smscore_sendrequest_and_wait(coredev, msg,
+                                               msg->xMsgHeader. msgLength,
+                                               &coredev->ir_init_done);
+
+                               kfree(buffer);
+                       } else
+                               sms_err
+                               ("Sending IR initialization message failed");
+               }
+       } else
+               sms_info("IR port has not been detected");
+
+       return 0;
+}
+
 /**
  * sets initial device mode and notifies client hotplugs that device is ready
  *
@@ -459,6 +499,7 @@ int smscore_start_device(struct smscore_device_t *coredev)
        kmutex_lock(&g_smscore_deviceslock);
 
        rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+       smscore_init_ir(coredev);
 
        sms_info("device %p started, rc %d", coredev, rc);
 
@@ -468,29 +509,19 @@ int smscore_start_device(struct smscore_device_t *coredev)
 }
 EXPORT_SYMBOL_GPL(smscore_start_device);
 
-static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
-                                       void *buffer, size_t size,
-                                       struct completion *completion)
-{
-       int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
-       if (rc < 0) {
-               sms_info("sendrequest returned error %d", rc);
-               return rc;
-       }
-
-       return wait_for_completion_timeout(completion,
-                                          msecs_to_jiffies(10000)) ?
-                                               0 : -ETIME;
-}
 
 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
                                         void *buffer, size_t size)
 {
        struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
        struct SmsMsgHdr_ST *msg;
-       u32 mem_address = firmware->StartAddress;
+       u32 mem_address;
        u8 *payload = firmware->Payload;
        int rc = 0;
+       firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
+       firmware->Length = le32_to_cpu(firmware->Length);
+
+       mem_address = firmware->StartAddress;
 
        sms_info("loading FW to addr 0x%x size %d",
                 mem_address, firmware->Length);
@@ -657,6 +688,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
 
        kmutex_lock(&g_smscore_deviceslock);
 
+       /* Release input device (IR) resources */
+       sms_ir_exit(coredev);
+
        smscore_notify_clients(coredev);
        smscore_notify_callbacks(coredev, NULL, 0);
 
@@ -664,7 +698,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
         * onresponse must no longer be called */
 
        while (1) {
-               while ((cb = smscore_getbuffer(coredev))) {
+               while (!list_empty(&coredev->buffers)) {
+                       cb = (struct smscore_buffer_t *) coredev->buffers.next;
+                       list_del(&cb->entry);
                        kfree(cb);
                        num_buffers++;
                }
@@ -685,8 +721,10 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
 
        if (coredev->common_buffer)
                dma_free_coherent(NULL, coredev->common_buffer_size,
-                                 coredev->common_buffer,
-                                 coredev->common_buffer_phys);
+                       coredev->common_buffer, coredev->common_buffer_phys);
+
+       if (coredev->fw_buf != NULL)
+               kfree(coredev->fw_buf);
 
        list_del(&coredev->entry);
        kfree(coredev);
@@ -746,7 +784,7 @@ static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
        /*BDA*/
        {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
        /*ISDBT*/
-       {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
+       {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
        /*ISDBTBDA*/
        {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
        /*CMMB*/
@@ -870,7 +908,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
                coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
        }
 
-       if (rc != 0)
+       if (rc < 0)
                sms_err("return error code %d.", rc);
        return rc;
 }
@@ -940,14 +978,11 @@ smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
  *
  */
 void smscore_onresponse(struct smscore_device_t *coredev,
-                       struct smscore_buffer_t *cb)
-{
-       struct SmsMsgHdr_ST *phdr =
-               (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
-       struct smscore_client_t *client =
-               smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+               struct smscore_buffer_t *cb) {
+       struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
+                       + cb->offset);
+       struct smscore_client_t *client;
        int rc = -EBUSY;
-
        static unsigned long last_sample_time; /* = 0; */
        static int data_total; /* = 0; */
        unsigned long time_now = jiffies_to_msecs(jiffies);
@@ -965,6 +1000,16 @@ void smscore_onresponse(struct smscore_device_t *coredev,
        }
 
        data_total += cb->size;
+       /* Do we need to re-route? */
+       if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
+                       (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
+               if (coredev->mode == DEVICE_MODE_DVBT_BDA)
+                       phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
+       }
+
+
+       client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+
        /* If no client registered for type & id,
         * check for control client where type is not registered */
        if (client)
@@ -1009,6 +1054,35 @@ void smscore_onresponse(struct smscore_device_t *coredev,
                case MSG_SMS_SLEEP_RESUME_COMP_IND:
                        complete(&coredev->resume_done);
                        break;
+               case MSG_SMS_GPIO_CONFIG_EX_RES:
+                       sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
+                       complete(&coredev->gpio_configuration_done);
+                       break;
+               case MSG_SMS_GPIO_SET_LEVEL_RES:
+                       sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
+                       complete(&coredev->gpio_set_level_done);
+                       break;
+               case MSG_SMS_GPIO_GET_LEVEL_RES:
+               {
+                       u32 *msgdata = (u32 *) phdr;
+                       coredev->gpio_get_res = msgdata[1];
+                       sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
+                                       coredev->gpio_get_res);
+                       complete(&coredev->gpio_get_level_done);
+                       break;
+               }
+               case MSG_SMS_START_IR_RES:
+                       complete(&coredev->ir_init_done);
+                       break;
+               case MSG_SMS_IR_SAMPLES_IND:
+                       sms_ir_event(coredev,
+                               (const char *)
+                               ((char *)phdr
+                               + sizeof(struct SmsMsgHdr_ST)),
+                               (int)phdr->msgLength
+                               - sizeof(struct SmsMsgHdr_ST));
+                       break;
+
                default:
                        break;
                }
@@ -1030,12 +1104,24 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
        struct smscore_buffer_t *cb = NULL;
        unsigned long flags;
 
+       DEFINE_WAIT(wait);
+
        spin_lock_irqsave(&coredev->bufferslock, flags);
 
-       if (!list_empty(&coredev->buffers)) {
-               cb = (struct smscore_buffer_t *) coredev->buffers.next;
-               list_del(&cb->entry);
-       }
+       /* This function must return a valid buffer, since the buffer list is
+        * finite, we check that there is an available buffer, if not, we wait
+        * until such buffer become available.
+        */
+
+       prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
+
+       if (list_empty(&coredev->buffers))
+               schedule();
+
+       finish_wait(&coredev->buffer_mng_waitq, &wait);
+
+       cb = (struct smscore_buffer_t *) coredev->buffers.next;
+       list_del(&cb->entry);
 
        spin_unlock_irqrestore(&coredev->bufferslock, flags);
 
@@ -1052,8 +1138,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer);
  *
  */
 void smscore_putbuffer(struct smscore_device_t *coredev,
-                      struct smscore_buffer_t *cb)
-{
+               struct smscore_buffer_t *cb) {
+       wake_up_interruptible(&coredev->buffer_mng_waitq);
        list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
 }
 EXPORT_SYMBOL_GPL(smscore_putbuffer);
@@ -1210,8 +1296,9 @@ int smsclient_sendrequest(struct smscore_client_t *client,
 EXPORT_SYMBOL_GPL(smsclient_sendrequest);
 
 
+/* old GPIO managments implementation */
 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
-                          struct smscore_gpio_config *pinconfig)
+                          struct smscore_config_gpio *pinconfig)
 {
        struct {
                struct SmsMsgHdr_ST hdr;
@@ -1280,35 +1367,254 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
                                            &msg, sizeof(msg));
 }
 
-static int __init smscore_module_init(void)
-{
-       int rc = 0;
+/* new GPIO managment implementation */
+static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
+               u32 *pGroupNum, u32 *pGroupCfg) {
+
+       *pGroupCfg = 1;
+
+       if (PinNum >= 0 && PinNum <= 1) {
+               *pTranslatedPinNum = 0;
+               *pGroupNum = 9;
+               *pGroupCfg = 2;
+       } else if (PinNum >= 2 && PinNum <= 6) {
+               *pTranslatedPinNum = 2;
+               *pGroupNum = 0;
+               *pGroupCfg = 2;
+       } else if (PinNum >= 7 && PinNum <= 11) {
+               *pTranslatedPinNum = 7;
+               *pGroupNum = 1;
+       } else if (PinNum >= 12 && PinNum <= 15) {
+               *pTranslatedPinNum = 12;
+               *pGroupNum = 2;
+               *pGroupCfg = 3;
+       } else if (PinNum == 16) {
+               *pTranslatedPinNum = 16;
+               *pGroupNum = 23;
+       } else if (PinNum >= 17 && PinNum <= 24) {
+               *pTranslatedPinNum = 17;
+               *pGroupNum = 3;
+       } else if (PinNum == 25) {
+               *pTranslatedPinNum = 25;
+               *pGroupNum = 6;
+       } else if (PinNum >= 26 && PinNum <= 28) {
+               *pTranslatedPinNum = 26;
+               *pGroupNum = 4;
+       } else if (PinNum == 29) {
+               *pTranslatedPinNum = 29;
+               *pGroupNum = 5;
+               *pGroupCfg = 2;
+       } else if (PinNum == 30) {
+               *pTranslatedPinNum = 30;
+               *pGroupNum = 8;
+       } else if (PinNum == 31) {
+               *pTranslatedPinNum = 31;
+               *pGroupNum = 17;
+       } else
+               return -1;
 
-       INIT_LIST_HEAD(&g_smscore_notifyees);
-       INIT_LIST_HEAD(&g_smscore_devices);
-       kmutex_init(&g_smscore_deviceslock);
+       *pGroupCfg <<= 24;
 
-       INIT_LIST_HEAD(&g_smscore_registry);
-       kmutex_init(&g_smscore_registrylock);
+       return 0;
+}
+
+int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+               struct smscore_gpio_config *pGpioConfig) {
+
+       u32 totalLen;
+       u32 TranslatedPinNum;
+       u32 GroupNum;
+       u32 ElectricChar;
+       u32 groupCfg;
+       void *buffer;
+       int rc;
+
+       struct SetGpioMsg {
+               struct SmsMsgHdr_ST xMsgHeader;
+               u32 msgData[6];
+       } *pMsg;
+
+
+       if (PinNum > MAX_GPIO_PIN_NUMBER)
+               return -EINVAL;
+
+       if (pGpioConfig == NULL)
+               return -EINVAL;
+
+       totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
+
+       buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       if (!buffer)
+               return -ENOMEM;
+
+       pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+       pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       pMsg->xMsgHeader.msgDstId = HIF_TASK;
+       pMsg->xMsgHeader.msgFlags = 0;
+       pMsg->xMsgHeader.msgLength = (u16) totalLen;
+       pMsg->msgData[0] = PinNum;
+
+       if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
+               pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
+               if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
+                               &groupCfg) != 0)
+                       return -EINVAL;
+
+               pMsg->msgData[1] = TranslatedPinNum;
+               pMsg->msgData[2] = GroupNum;
+               ElectricChar = (pGpioConfig->PullUpDown)
+                               | (pGpioConfig->InputCharacteristics << 2)
+                               | (pGpioConfig->OutputSlewRate << 3)
+                               | (pGpioConfig->OutputDriving << 4);
+               pMsg->msgData[3] = ElectricChar;
+               pMsg->msgData[4] = pGpioConfig->Direction;
+               pMsg->msgData[5] = groupCfg;
+       } else {
+               pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
+               pMsg->msgData[1] = pGpioConfig->PullUpDown;
+               pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
+               pMsg->msgData[3] = pGpioConfig->OutputDriving;
+               pMsg->msgData[4] = pGpioConfig->Direction;
+               pMsg->msgData[5] = 0;
+       }
+
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+       rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+                       &coredev->gpio_configuration_done);
+
+       if (rc != 0) {
+               if (rc == -ETIME)
+                       sms_err("smscore_gpio_configure timeout");
+               else
+                       sms_err("smscore_gpio_configure error");
+       }
+       kfree(buffer);
+
+       return rc;
+}
+
+int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 NewLevel) {
+
+       u32 totalLen;
+       int rc;
+       void *buffer;
+
+       struct SetGpioMsg {
+               struct SmsMsgHdr_ST xMsgHeader;
+               u32 msgData[3]; /* keep it 3 ! */
+       } *pMsg;
+
+       if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
+                       (PinNum > MAX_GPIO_PIN_NUMBER))
+               return -EINVAL;
 
+       totalLen = sizeof(struct SmsMsgHdr_ST) +
+                       (3 * sizeof(u32)); /* keep it 3 ! */
 
+       buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       if (!buffer)
+               return -ENOMEM;
 
+       pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
 
+       pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       pMsg->xMsgHeader.msgDstId = HIF_TASK;
+       pMsg->xMsgHeader.msgFlags = 0;
+       pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
+       pMsg->xMsgHeader.msgLength = (u16) totalLen;
+       pMsg->msgData[0] = PinNum;
+       pMsg->msgData[1] = NewLevel;
 
+       /* Send message to SMS */
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+       rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+                       &coredev->gpio_set_level_done);
+
+       if (rc != 0) {
+               if (rc == -ETIME)
+                       sms_err("smscore_gpio_set_level timeout");
+               else
+                       sms_err("smscore_gpio_set_level error");
+       }
+       kfree(buffer);
 
        return rc;
-       sms_debug("rc %d", rc);
+}
+
+int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 *level) {
+
+       u32 totalLen;
+       int rc;
+       void *buffer;
+
+       struct SetGpioMsg {
+               struct SmsMsgHdr_ST xMsgHeader;
+               u32 msgData[2];
+       } *pMsg;
+
+
+       if (PinNum > MAX_GPIO_PIN_NUMBER)
+               return -EINVAL;
+
+       totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
+
+       buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       if (!buffer)
+               return -ENOMEM;
+
+       pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+       pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       pMsg->xMsgHeader.msgDstId = HIF_TASK;
+       pMsg->xMsgHeader.msgFlags = 0;
+       pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
+       pMsg->xMsgHeader.msgLength = (u16) totalLen;
+       pMsg->msgData[0] = PinNum;
+       pMsg->msgData[1] = 0;
+
+       /* Send message to SMS */
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+       rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+                       &coredev->gpio_get_level_done);
+
+       if (rc != 0) {
+               if (rc == -ETIME)
+                       sms_err("smscore_gpio_get_level timeout");
+               else
+                       sms_err("smscore_gpio_get_level error");
+       }
+       kfree(buffer);
+
+       /* Its a race between other gpio_get_level() and the copy of the single
+        * global 'coredev->gpio_get_res' to  the function's variable 'level'
+        */
+       *level = coredev->gpio_get_res;
 
        return rc;
 }
 
-static void __exit smscore_module_exit(void)
+static int __init smscore_module_init(void)
 {
+       int rc = 0;
 
+       INIT_LIST_HEAD(&g_smscore_notifyees);
+       INIT_LIST_HEAD(&g_smscore_devices);
+       kmutex_init(&g_smscore_deviceslock);
 
+       INIT_LIST_HEAD(&g_smscore_registry);
+       kmutex_init(&g_smscore_registrylock);
 
+       return rc;
+}
 
-
+static void __exit smscore_module_exit(void)
+{
        kmutex_lock(&g_smscore_deviceslock);
        while (!list_empty(&g_smscore_notifyees)) {
                struct smscore_device_notifyee_t *notifyee =
index 548de9056e8b97b0f567d9cbf948ecb10891b6cc..f1108c64e895eb4ad2914aebb41cb6ef78a5ab3d 100644 (file)
@@ -1,26 +1,26 @@
-/*
- *  Driver for the Siano SMS1xxx USB dongle
- *
- *  author: Anatoly Greenblat
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  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 __smscoreapi_h__
-#define __smscoreapi_h__
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_CORE_API_H__
+#define __SMS_CORE_API_H__
 
 #include <linux/version.h>
 #include <linux/device.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
 #include <linux/types.h>
-#include <asm/page.h>
 #include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
 
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
+#include <asm/page.h>
 
+#include "smsir.h"
 
 #define kmutex_init(_p_) mutex_init(_p_)
 #define kmutex_lock(_p_) mutex_lock(_p_)
 #define min(a, b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#define SMS_ALLOC_ALIGNMENT                                    128
-#define SMS_DMA_ALIGNMENT                                      16
+#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS                 (10000)
+#define SMS_ALLOC_ALIGNMENT                            128
+#define SMS_DMA_ALIGNMENT                              16
 #define SMS_ALIGN_ADDRESS(addr) \
        ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
 
-#define SMS_DEVICE_FAMILY2                                     1
-#define SMS_ROM_NO_RESPONSE                                    2
+#define SMS_DEVICE_FAMILY2                             1
+#define SMS_ROM_NO_RESPONSE                            2
 #define SMS_DEVICE_NOT_READY                           0x8000000
 
 enum sms_device_type_st {
@@ -83,13 +83,13 @@ typedef void (*onremove_t)(void *context);
 struct smscore_buffer_t {
        /* public members, once passed to clients can be changed freely */
        struct list_head entry;
-       int                             size;
-       int                             offset;
+       int size;
+       int offset;
 
        /* private members, read-only for clients */
-       void                    *p;
-       dma_addr_t              phys;
-       unsigned long   offset_in_common;
+       void *p;
+       dma_addr_t phys;
+       unsigned long offset_in_common;
 };
 
 struct smsdevice_params_t {
@@ -116,10 +116,63 @@ struct smsclient_params_t {
        int                             data_type;
        onresponse_t    onresponse_handler;
        onremove_t              onremove_handler;
-
        void                    *context;
 };
 
+struct smscore_device_t {
+       struct list_head entry;
+
+       struct list_head clients;
+       struct list_head subclients;
+       spinlock_t clientslock;
+
+       struct list_head buffers;
+       spinlock_t bufferslock;
+       int num_buffers;
+
+       void *common_buffer;
+       int common_buffer_size;
+       dma_addr_t common_buffer_phys;
+
+       void *context;
+       struct device *device;
+
+       char devpath[32];
+       unsigned long device_flags;
+
+       setmode_t setmode_handler;
+       detectmode_t detectmode_handler;
+       sendrequest_t sendrequest_handler;
+       preload_t preload_handler;
+       postload_t postload_handler;
+
+       int mode, modes_supported;
+
+       /* host <--> device messages */
+       struct completion version_ex_done, data_download_done, trigger_done;
+       struct completion init_device_done, reload_start_done, resume_done;
+       struct completion gpio_configuration_done, gpio_set_level_done;
+       struct completion gpio_get_level_done, ir_init_done;
+
+       /* Buffer management */
+       wait_queue_head_t buffer_mng_waitq;
+
+       /* GPIO */
+       int gpio_get_res;
+
+       /* Target hardware board */
+       int board_id;
+
+       /* Firmware */
+       u8 *fw_buf;
+       u32 fw_buf_size;
+
+       /* Infrared (IR) */
+       struct ir_t ir;
+
+       int led_state;
+};
+
 /* GPIO definitions for antenna frequency domain control (SMS8021) */
 #define SMS_ANTENNA_GPIO_0                                     1
 #define SMS_ANTENNA_GPIO_1                                     0
@@ -154,18 +207,15 @@ struct smsclient_params_t {
 #define MSG_SMS_INIT_DEVICE_RES                                579
 #define MSG_SMS_ADD_PID_FILTER_REQ                     601
 #define MSG_SMS_ADD_PID_FILTER_RES                     602
-#define MSG_SMS_REMOVE_PID_FILTER_REQ          603
-#define MSG_SMS_REMOVE_PID_FILTER_RES          604
-#define MSG_SMS_DAB_CHANNEL                                    607
-#define MSG_SMS_GET_PID_FILTER_LIST_REQ                608
-#define MSG_SMS_GET_PID_FILTER_LIST_RES                609
-#define MSG_SMS_GET_STATISTICS_REQ                     615
-#define MSG_SMS_GET_STATISTICS_RES                     616
-#define MSG_SMS_SET_ANTENNA_CONFIG_REQ         651
-#define MSG_SMS_SET_ANTENNA_CONFIG_RES         652
-#define MSG_SMS_GET_STATISTICS_EX_REQ          653
-#define MSG_SMS_GET_STATISTICS_EX_RES          654
-#define MSG_SMS_SLEEP_RESUME_COMP_IND          655
+#define MSG_SMS_REMOVE_PID_FILTER_REQ                  603
+#define MSG_SMS_REMOVE_PID_FILTER_RES                  604
+#define MSG_SMS_DAB_CHANNEL                            607
+#define MSG_SMS_GET_PID_FILTER_LIST_REQ                        608
+#define MSG_SMS_GET_PID_FILTER_LIST_RES                        609
+#define MSG_SMS_HO_PER_SLICES_IND                      630
+#define MSG_SMS_SET_ANTENNA_CONFIG_REQ                 651
+#define MSG_SMS_SET_ANTENNA_CONFIG_RES                 652
+#define MSG_SMS_SLEEP_RESUME_COMP_IND                  655
 #define MSG_SMS_DATA_DOWNLOAD_REQ                      660
 #define MSG_SMS_DATA_DOWNLOAD_RES                      661
 #define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ         664
@@ -190,14 +240,31 @@ struct smsclient_params_t {
 #define MSG_SMS_GPIO_CONFIG_EX_RES                     713
 #define MSG_SMS_ISDBT_TUNE_REQ                         776
 #define MSG_SMS_ISDBT_TUNE_RES                         777
+#define MSG_SMS_TRANSMISSION_IND                       782
+#define MSG_SMS_START_IR_REQ                           800
+#define MSG_SMS_START_IR_RES                           801
+#define MSG_SMS_IR_SAMPLES_IND                         802
+#define MSG_SMS_SIGNAL_DETECTED_IND                    827
+#define MSG_SMS_NO_SIGNAL_IND                          828
 
 #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
        (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
        (ptr)->msgLength = len; (ptr)->msgFlags = 0; \
 } while (0)
+
 #define SMS_INIT_MSG(ptr, type, len) \
        SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
 
+enum SMS_DVB3_EVENTS {
+       DVB3_EVENT_INIT = 0,
+       DVB3_EVENT_SLEEP,
+       DVB3_EVENT_HOTPLUG,
+       DVB3_EVENT_FE_LOCK,
+       DVB3_EVENT_FE_UNLOCK,
+       DVB3_EVENT_UNC_OK,
+       DVB3_EVENT_UNC_ERR
+};
+
 enum SMS_DEVICE_MODE {
        DEVICE_MODE_NONE = -1,
        DEVICE_MODE_DVBT = 0,
@@ -221,8 +288,13 @@ struct SmsMsgHdr_ST {
 };
 
 struct SmsMsgData_ST {
-       struct SmsMsgHdr_ST     xMsgHeader;
-       u32                     msgData[1];
+       struct SmsMsgHdr_ST xMsgHeader;
+       u32 msgData[1];
+};
+
+struct SmsMsgData_ST2 {
+       struct SmsMsgHdr_ST xMsgHeader;
+       u32 msgData[2];
 };
 
 struct SmsDataDownload_ST {
@@ -238,11 +310,12 @@ struct SmsVersionRes_ST {
        u8              Step; /* 0 - Step A */
        u8              MetalFix; /* 0 - Metal 0 */
 
-       u8              FirmwareId; /* 0xFF ï¿½ ROM, otherwise the
-                                    * value indicated by
-                                    * SMSHOSTLIB_DEVICE_MODES_E */
-       u8              SupportedProtocols; /* Bitwise OR combination of
+       /* FirmwareId 0xFF if ROM, otherwise the
+        * value indicated by SMSHOSTLIB_DEVICE_MODES_E */
+       u8 FirmwareId;
+       /* SupportedProtocols Bitwise OR combination of
                                             * supported protocols */
+       u8 SupportedProtocols;
 
        u8              VersionMajor;
        u8              VersionMinor;
@@ -264,86 +337,219 @@ struct SmsFirmware_ST {
        u8                      Payload[1];
 };
 
-struct SMSHOSTLIB_STATISTICS_ST {
-       u32 Reserved; /* Reserved */
+/* Statistics information returned as response for
+ * SmsHostApiGetStatistics_Req */
+struct SMSHOSTLIB_STATISTICS_S {
+       u32 Reserved;           /* Reserved */
 
        /* Common parameters */
-       u32 IsRfLocked; /* 0 - not locked, 1 - locked */
-       u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
-       u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+       u32 IsRfLocked;         /* 0 - not locked, 1 - locked */
+       u32 IsDemodLocked;      /* 0 - not locked, 1 - locked */
+       u32 IsExternalLNAOn;    /* 0 - external LNA off, 1 - external LNA on */
 
        /* Reception quality */
-       s32  SNR; /* dB */
-       u32 BER; /* Post Viterbi BER [1E-5] */
-       u32 FIB_CRC;    /* CRC errors percentage, valid only for DAB */
-       u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A,
-                    * valid only for DVB-T/H */
-       u32 MFER; /* DVB-H frame error rate in percentage,
-                  * 0xFFFFFFFF indicate N/A, valid only for DVB-H */
-       s32  RSSI; /* dBm */
-       s32  InBandPwr; /* In band power in dBM */
-       s32  CarrierOffset; /* Carrier Offset in bin/1024 */
-
-       /* Transmission parameters, valid only for DVB-T/H */
-       u32 Frequency; /* Frequency in Hz */
-       u32 Bandwidth; /* Bandwidth in MHz */
-       u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
-                              * for DVB-T/H FFT mode carriers in Kilos */
-       u32 ModemState; /* from SMS_DvbModemState_ET */
-       u32 GuardInterval; /* Guard Interval, 1 divided by value */
-       u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */
-       u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */
-       u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */
-       u32 Constellation; /* Constellation from SMS_Constellation_ET */
+       s32 SNR;                /* dB */
+       u32 BER;                /* Post Viterbi BER [1E-5] */
+       u32 FIB_CRC;            /* CRC errors percentage, valid only for DAB */
+       u32 TS_PER;             /* Transport stream PER,
+       0xFFFFFFFF indicate N/A, valid only for DVB-T/H */
+       u32 MFER;               /* DVB-H frame error rate in percentage,
+       0xFFFFFFFF indicate N/A, valid only for DVB-H */
+       s32 RSSI;               /* dBm */
+       s32 InBandPwr;          /* In band power in dBM */
+       s32 CarrierOffset;      /* Carrier Offset in bin/1024 */
+
+       /* Transmission parameters */
+       u32 Frequency;          /* Frequency in Hz */
+       u32 Bandwidth;          /* Bandwidth in MHz, valid only for DVB-T/H */
+       u32 TransmissionMode;   /* Transmission Mode, for DAB modes 1-4,
+       for DVB-T/H FFT mode carriers in Kilos */
+       u32 ModemState;         /* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
+       valid only for DVB-T/H */
+       u32 GuardInterval;      /* Guard Interval from
+       SMSHOSTLIB_GUARD_INTERVALS_ET,  valid only for DVB-T/H */
+       u32 CodeRate;           /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+       valid only for DVB-T/H */
+       u32 LPCodeRate;         /* Low Priority Code Rate from
+       SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */
+       u32 Hierarchy;          /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET,
+       valid only for DVB-T/H */
+       u32 Constellation;      /* Constellation from
+       SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */
 
        /* Burst parameters, valid only for DVB-H */
-       u32 BurstSize; /* Current burst size in bytes */
-       u32 BurstDuration; /* Current burst duration in mSec */
-       u32 BurstCycleTime; /* Current burst cycle time in mSec */
-       u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec,
-                                      * as calculated by demodulator */
-       u32 NumOfRows; /* Number of rows in MPE table */
-       u32 NumOfPaddCols; /* Number of padding columns in MPE table */
-       u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */
-       /* Burst parameters */
-       u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
-       u32 TotalTSPackets; /* Total number of transport-stream packets */
-       u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
-                               * errors after MPE RS decoding */
-       u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors
-                                 * after MPE RS decoding */
-       u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
-                                   * by MPE RS decoding */
-
+       u32 BurstSize;          /* Current burst size in bytes,
+       valid only for DVB-H */
+       u32 BurstDuration;      /* Current burst duration in mSec,
+       valid only for DVB-H */
+       u32 BurstCycleTime;     /* Current burst cycle time in mSec,
+       valid only for DVB-H */
+       u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec,
+       as calculated by demodulator, valid only for DVB-H */
+       u32 NumOfRows;          /* Number of rows in MPE table,
+       valid only for DVB-H */
+       u32 NumOfPaddCols;      /* Number of padding columns in MPE table,
+       valid only for DVB-H */
+       u32 NumOfPunctCols;     /* Number of puncturing columns in MPE table,
+       valid only for DVB-H */
+       u32 ErrorTSPackets;     /* Number of erroneous
+       transport-stream packets */
+       u32 TotalTSPackets;     /* Total number of transport-stream packets */
+       u32 NumOfValidMpeTlbs;  /* Number of MPE tables which do not include
+       errors after MPE RS decoding */
+       u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors
+       after MPE RS decoding */
+       u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were
+       corrected by MPE RS decoding */
        /* Common params */
-       u32 BERErrorCount; /* Number of errornous SYNC bits. */
-       u32 BERBitCount; /* Total number of SYNC bits. */
+       u32 BERErrorCount;      /* Number of errornous SYNC bits. */
+       u32 BERBitCount;        /* Total number of SYNC bits. */
 
        /* Interface information */
-       u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+       u32 SmsToHostTxErrors;  /* Total number of transmission errors. */
 
        /* DAB/T-DMB */
-       u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
+       u32 PreBER;             /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
 
        /* DVB-H TPS parameters */
-       u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
-                    * if set to 0xFFFFFFFF cell_id not yet recovered */
+       u32 CellId;             /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+        if set to 0xFFFFFFFF cell_id not yet recovered */
+       u32 DvbhSrvIndHP;       /* DVB-H service indication info, bit 1 -
+       Time Slicing indicator, bit 0 - MPE-FEC indicator */
+       u32 DvbhSrvIndLP;       /* DVB-H service indication info, bit 1 -
+       Time Slicing indicator, bit 0 - MPE-FEC indicator */
 
+       u32 NumMPEReceived;     /* DVB-H, Num MPE section received */
+
+       u32 ReservedFields[10]; /* Reserved */
 };
 
-struct SmsMsgStatisticsInfo_ST {
-       u32 RequestResult;
+struct PID_STATISTICS_DATA_S {
+       struct PID_BURST_S {
+               u32 size;
+               u32 padding_cols;
+               u32 punct_cols;
+               u32 duration;
+               u32 cycle;
+               u32 calc_cycle;
+       } burst;
+
+       u32 tot_tbl_cnt;
+       u32 invalid_tbl_cnt;
+       u32 tot_cor_tbl;
+};
 
-       struct SMSHOSTLIB_STATISTICS_ST Stat;
+struct PID_DATA_S {
+       u32 pid;
+       u32 num_rows;
+       struct PID_STATISTICS_DATA_S pid_statistics;
+};
 
-       /* Split the calc of the SNR in DAB */
-       u32 Signal; /* dB */
-       u32 Noise; /* dB */
+#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1)
+#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth)
+#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \
+       if (_stat.TransmissionMode == 0) \
+               _stat.TransmissionMode = 2; \
+       else if (_stat.TransmissionMode == 1) \
+               _stat.TransmissionMode = 8; \
+               else \
+                       _stat.TransmissionMode = 4;
+
+struct TRANSMISSION_STATISTICS_S {
+       u32 Frequency;          /* Frequency in Hz */
+       u32 Bandwidth;          /* Bandwidth in MHz */
+       u32 TransmissionMode;   /* FFT mode carriers in Kilos */
+       u32 GuardInterval;      /* Guard Interval from
+       SMSHOSTLIB_GUARD_INTERVALS_ET */
+       u32 CodeRate;           /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
+       u32 LPCodeRate;         /* Low Priority Code Rate from
+       SMSHOSTLIB_CODE_RATE_ET */
+       u32 Hierarchy;          /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */
+       u32 Constellation;      /* Constellation from
+       SMSHOSTLIB_CONSTELLATION_ET */
 
+       /* DVB-H TPS parameters */
+       u32 CellId;             /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+        if set to 0xFFFFFFFF cell_id not yet recovered */
+       u32 DvbhSrvIndHP;       /* DVB-H service indication info, bit 1 -
+        Time Slicing indicator, bit 0 - MPE-FEC indicator */
+       u32 DvbhSrvIndLP;       /* DVB-H service indication info, bit 1 -
+        Time Slicing indicator, bit 0 - MPE-FEC indicator */
+       u32 IsDemodLocked;      /* 0 - not locked, 1 - locked */
 };
 
+struct RECEPTION_STATISTICS_S {
+       u32 IsRfLocked;         /* 0 - not locked, 1 - locked */
+       u32 IsDemodLocked;      /* 0 - not locked, 1 - locked */
+       u32 IsExternalLNAOn;    /* 0 - external LNA off, 1 - external LNA on */
+
+       u32 ModemState;         /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+       s32 SNR;                /* dB */
+       u32 BER;                /* Post Viterbi BER [1E-5] */
+       u32 BERErrorCount;      /* Number of erronous SYNC bits. */
+       u32 BERBitCount;        /* Total number of SYNC bits. */
+       u32 TS_PER;             /* Transport stream PER,
+       0xFFFFFFFF indicate N/A */
+       u32 MFER;               /* DVB-H frame error rate in percentage,
+       0xFFFFFFFF indicate N/A, valid only for DVB-H */
+       s32 RSSI;               /* dBm */
+       s32 InBandPwr;          /* In band power in dBM */
+       s32 CarrierOffset;      /* Carrier Offset in bin/1024 */
+       u32 ErrorTSPackets;     /* Number of erroneous
+       transport-stream packets */
+       u32 TotalTSPackets;     /* Total number of transport-stream packets */
+
+       s32 MRC_SNR;            /* dB */
+       s32 MRC_RSSI;           /* dBm */
+       s32 MRC_InBandPwr;      /* In band power in dBM */
+};
 
-struct smscore_gpio_config {
+
+/* Statistics information returned as response for
+ * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */
+struct SMSHOSTLIB_STATISTICS_DVB_S {
+       /* Reception */
+       struct RECEPTION_STATISTICS_S ReceptionData;
+
+       /* Transmission parameters */
+       struct TRANSMISSION_STATISTICS_S TransmissionData;
+
+       /* Burst parameters, valid only for DVB-H */
+#define        SRVM_MAX_PID_FILTERS 8
+       struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS];
+};
+
+struct SRVM_SIGNAL_STATUS_S {
+       u32 result;
+       u32 snr;
+       u32 tsPackets;
+       u32 etsPackets;
+       u32 constellation;
+       u32 hpCode;
+       u32 tpsSrvIndLP;
+       u32 tpsSrvIndHP;
+       u32 cellId;
+       u32 reason;
+
+       s32 inBandPower;
+       u32 requestId;
+};
+
+struct SMSHOSTLIB_I2C_REQ_ST {
+       u32     DeviceAddress; /* I2c device address */
+       u32     WriteCount; /* number of bytes to write */
+       u32     ReadCount; /* number of bytes to read */
+       u8      Data[1];
+};
+
+struct SMSHOSTLIB_I2C_RES_ST {
+       u32     Status; /* non-zero value in case of failure */
+       u32     ReadCount; /* number of bytes read */
+       u8      Data[1];
+};
+
+
+struct smscore_config_gpio {
 #define SMS_GPIO_DIRECTION_INPUT  0
 #define SMS_GPIO_DIRECTION_OUTPUT 1
        u8 direction;
@@ -369,6 +575,47 @@ struct smscore_gpio_config {
        u8 outputdriving;
 };
 
+struct smscore_gpio_config {
+#define SMS_GPIO_DIRECTION_INPUT  0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+       u8 Direction;
+
+#define SMS_GPIO_PULL_UP_DOWN_NONE     0
+#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1
+#define SMS_GPIO_PULL_UP_DOWN_PULLUP   2
+#define SMS_GPIO_PULL_UP_DOWN_KEEPER   3
+       u8 PullUpDown;
+
+#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL  0
+#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1
+       u8 InputCharacteristics;
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW         1 /* 10xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST         0 /* 10xx */
+
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS    0 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS     1 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS     2 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS     3 /* 11xx */
+       u8 OutputSlewRate;
+
+#define SMS_GPIO_OUTPUT_DRIVING_S_4mA          0 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_8mA          1 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_12mA         2 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_16mA         3 /* 10xx */
+
+#define SMS_GPIO_OUTPUT_DRIVING_1_5mA          0 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_2_8mA          1 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_4mA            2 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_7mA            3 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_10mA           4 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_11mA           5 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_14mA           6 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_16mA           7 /* 11xx */
+       u8 OutputDriving;
+};
+
 extern void smscore_registry_setmode(char *devpath, int mode);
 extern int smscore_registry_getmode(char *devpath);
 
@@ -410,10 +657,19 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
 extern void smscore_putbuffer(struct smscore_device_t *coredev,
                              struct smscore_buffer_t *cb);
 
+/* old GPIO managment */
 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
-                          struct smscore_gpio_config *pinconfig);
+                          struct smscore_config_gpio *pinconfig);
 int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
 
+/* new GPIO managment */
+extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+               struct smscore_gpio_config *pGpioConfig);
+extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 NewLevel);
+extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 *level);
+
 void smscore_set_board_id(struct smscore_device_t *core, int id);
 int smscore_get_board_id(struct smscore_device_t *core);
 
@@ -442,4 +698,4 @@ int smscore_led_state(struct smscore_device_t *core, int led);
        dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
 
 
-#endif /* __smscoreapi_h__ */
+#endif /* __SMS_CORE_API_H__ */
index ba080b95befbf5cda1d3943a4d34eaeab5bf60ee..3ee1c3902c56dcc9d56a26380e5dadb07459cd99 100644 (file)
@@ -1,28 +1,34 @@
-/*
- *  Driver for the Siano SMS1xxx USB dongle
- *
- *  Author: Uri Shkolni
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  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.
- */
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
 
 #include <linux/module.h>
 #include <linux/init.h>
 
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
 #include "smscoreapi.h"
+#include "smsendian.h"
 #include "sms-cards.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -39,12 +45,15 @@ struct smsdvb_client_t {
        struct dvb_frontend     frontend;
 
        fe_status_t             fe_status;
-       int                     fe_ber, fe_snr, fe_unc, fe_signal_strength;
 
-       struct completion       tune_done, stat_done;
+       struct completion       tune_done;
 
        /* todo: save freq/band instead whole struct */
        struct dvb_frontend_parameters fe_params;
+
+       struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
+       int event_fe_state;
+       int event_unc_state;
 };
 
 static struct list_head g_smsdvb_clients;
@@ -54,11 +63,69 @@ static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
 
+/* Events that may come from DVB v3 adapter */
+static void sms_board_dvb3_event(struct smsdvb_client_t *client,
+               enum SMS_DVB3_EVENTS event) {
+
+       struct smscore_device_t *coredev = client->coredev;
+       switch (event) {
+       case DVB3_EVENT_INIT:
+               sms_debug("DVB3_EVENT_INIT");
+               sms_board_event(coredev, BOARD_EVENT_BIND);
+               break;
+       case DVB3_EVENT_SLEEP:
+               sms_debug("DVB3_EVENT_SLEEP");
+               sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
+               break;
+       case DVB3_EVENT_HOTPLUG:
+               sms_debug("DVB3_EVENT_HOTPLUG");
+               sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
+               break;
+       case DVB3_EVENT_FE_LOCK:
+               if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
+                       client->event_fe_state = DVB3_EVENT_FE_LOCK;
+                       sms_debug("DVB3_EVENT_FE_LOCK");
+                       sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
+               }
+               break;
+       case DVB3_EVENT_FE_UNLOCK:
+               if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
+                       client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
+                       sms_debug("DVB3_EVENT_FE_UNLOCK");
+                       sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
+               }
+               break;
+       case DVB3_EVENT_UNC_OK:
+               if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
+                       client->event_unc_state = DVB3_EVENT_UNC_OK;
+                       sms_debug("DVB3_EVENT_UNC_OK");
+                       sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
+               }
+               break;
+       case DVB3_EVENT_UNC_ERR:
+               if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
+                       client->event_unc_state = DVB3_EVENT_UNC_ERR;
+                       sms_debug("DVB3_EVENT_UNC_ERR");
+                       sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
+               }
+               break;
+
+       default:
+               sms_err("Unknown dvb3 api event");
+               break;
+       }
+}
+
 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 {
        struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
-       struct SmsMsgHdr_ST *phdr =
-               (struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
+       struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
+                       + cb->offset);
+       u32 *pMsgData = (u32 *) phdr + 1;
+       /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
+       bool is_status_update = false;
+
+       smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
 
        switch (phdr->msgType) {
        case MSG_SMS_DVBT_BDA_DATA:
@@ -70,43 +137,110 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
                complete(&client->tune_done);
                break;
 
-       case MSG_SMS_GET_STATISTICS_RES:
-       {
-               struct SmsMsgStatisticsInfo_ST *p =
-                       (struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
-
-               if (p->Stat.IsDemodLocked) {
-                       client->fe_status = FE_HAS_SIGNAL |
-                                           FE_HAS_CARRIER |
-                                           FE_HAS_VITERBI |
-                                           FE_HAS_SYNC |
-                                           FE_HAS_LOCK;
-
-                       client->fe_snr = p->Stat.SNR;
-                       client->fe_ber = p->Stat.BER;
-                       client->fe_unc = p->Stat.BERErrorCount;
-
-                       if (p->Stat.InBandPwr < -95)
-                               client->fe_signal_strength = 0;
-                       else if (p->Stat.InBandPwr > -29)
-                               client->fe_signal_strength = 100;
-                       else
-                               client->fe_signal_strength =
-                                       (p->Stat.InBandPwr + 95) * 3 / 2;
+       case MSG_SMS_SIGNAL_DETECTED_IND:
+               sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
+               client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
+               is_status_update = true;
+               break;
+
+       case MSG_SMS_NO_SIGNAL_IND:
+               sms_info("MSG_SMS_NO_SIGNAL_IND");
+               client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
+               is_status_update = true;
+               break;
+
+       case MSG_SMS_TRANSMISSION_IND: {
+               sms_info("MSG_SMS_TRANSMISSION_IND");
+
+               pMsgData++;
+               memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
+                               sizeof(struct TRANSMISSION_STATISTICS_S));
+
+               /* Mo need to correct guard interval
+                * (as opposed to old statistics message).
+                */
+               CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
+               CORRECT_STAT_TRANSMISSON_MODE(
+                               client->sms_stat_dvb.TransmissionData);
+               is_status_update = true;
+               break;
+       }
+       case MSG_SMS_HO_PER_SLICES_IND: {
+               struct RECEPTION_STATISTICS_S *pReceptionData =
+                               &client->sms_stat_dvb.ReceptionData;
+               struct SRVM_SIGNAL_STATUS_S SignalStatusData;
+
+               /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
+               pMsgData++;
+               SignalStatusData.result = pMsgData[0];
+               SignalStatusData.snr = pMsgData[1];
+               SignalStatusData.inBandPower = (s32) pMsgData[2];
+               SignalStatusData.tsPackets = pMsgData[3];
+               SignalStatusData.etsPackets = pMsgData[4];
+               SignalStatusData.constellation = pMsgData[5];
+               SignalStatusData.hpCode = pMsgData[6];
+               SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
+               SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
+               SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
+               SignalStatusData.reason = pMsgData[10];
+               SignalStatusData.requestId = pMsgData[11];
+               pReceptionData->IsRfLocked = pMsgData[16];
+               pReceptionData->IsDemodLocked = pMsgData[17];
+               pReceptionData->ModemState = pMsgData[12];
+               pReceptionData->SNR = pMsgData[1];
+               pReceptionData->BER = pMsgData[13];
+               pReceptionData->RSSI = pMsgData[14];
+               CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
+
+               pReceptionData->InBandPwr = (s32) pMsgData[2];
+               pReceptionData->CarrierOffset = (s32) pMsgData[15];
+               pReceptionData->TotalTSPackets = pMsgData[3];
+               pReceptionData->ErrorTSPackets = pMsgData[4];
+
+               /* TS PER */
+               if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
+                               > 0) {
+                       pReceptionData->TS_PER = (SignalStatusData.etsPackets
+                                       * 100) / (SignalStatusData.tsPackets
+                                       + SignalStatusData.etsPackets);
                } else {
-                       client->fe_status = 0;
-                       client->fe_snr =
-                       client->fe_ber =
-                       client->fe_unc =
-                       client->fe_signal_strength = 0;
+                       pReceptionData->TS_PER = 0;
                }
 
-               complete(&client->stat_done);
-               break;
-       } }
+               pReceptionData->BERBitCount = pMsgData[18];
+               pReceptionData->BERErrorCount = pMsgData[19];
 
+               pReceptionData->MRC_SNR = pMsgData[20];
+               pReceptionData->MRC_InBandPwr = pMsgData[21];
+               pReceptionData->MRC_RSSI = pMsgData[22];
+
+               is_status_update = true;
+               break;
+       }
+       }
        smscore_putbuffer(client->coredev, cb);
 
+       if (is_status_update) {
+               if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
+                       client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
+                               | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+                       sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
+                       if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
+                                       == 0)
+                               sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
+                       else
+                               sms_board_dvb3_event(client,
+                                               DVB3_EVENT_UNC_ERR);
+
+               } else {
+                       /*client->fe_status =
+                               (phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
+                               0 : FE_HAS_SIGNAL;*/
+                       client->fe_status = 0;
+                       sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
+               }
+       }
+
        return 0;
 }
 
@@ -149,6 +283,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed)
        PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
        PidMsg.msgData[0] = feed->pid;
 
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
        return smsclient_sendrequest(client->smsclient,
                                     &PidMsg, sizeof(PidMsg));
 }
@@ -169,6 +304,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
        PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
        PidMsg.msgData[0] = feed->pid;
 
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
        return smsclient_sendrequest(client->smsclient,
                                     &PidMsg, sizeof(PidMsg));
 }
@@ -177,7 +313,10 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
                                        void *buffer, size_t size,
                                        struct completion *completion)
 {
-       int rc = smsclient_sendrequest(client->smsclient, buffer, size);
+       int rc;
+
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
+       rc = smsclient_sendrequest(client->smsclient, buffer, size);
        if (rc < 0)
                return rc;
 
@@ -186,83 +325,61 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
                                                0 : -ETIME;
 }
 
-static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
-{
-       struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
-                            DVBT_BDA_CONTROL_MSG_ID,
-                            HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
-       int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-                                             &client->stat_done);
-       if (ret < 0)
-               return ret;
-
-       if (client->fe_status & FE_HAS_LOCK)
-               sms_board_led_feedback(client->coredev,
-                                      (client->fe_unc == 0) ?
-                                      SMS_LED_HI : SMS_LED_LO);
-       else
-               sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-       return ret;
-}
-
 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *stat = client->fe_status;
+       *stat = client->fe_status;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *ber = client->fe_ber;
+       *ber = client->sms_stat_dvb.ReceptionData.BER;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *strength = client->fe_signal_strength;
+       if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
+               *strength = 0;
+               else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
+                       *strength = 100;
+               else
+                       *strength =
+                               (client->sms_stat_dvb.ReceptionData.InBandPwr
+                               + 95) * 3 / 2;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *snr = client->fe_snr;
+       *snr = client->sms_stat_dvb.ReceptionData.SNR;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *ucblocks = client->fe_unc;
+       *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
@@ -286,12 +403,15 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
                struct SmsMsgHdr_ST     Msg;
                u32             Data[3];
        } Msg;
-       int ret;
 
-       Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
-       Msg.Msg.msgDstId  = HIF_TASK;
-       Msg.Msg.msgFlags  = 0;
-       Msg.Msg.msgType   = MSG_SMS_RF_TUNE_REQ;
+       client->fe_status = FE_HAS_SIGNAL;
+       client->event_fe_state = -1;
+       client->event_unc_state = -1;
+
+       Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       Msg.Msg.msgDstId = HIF_TASK;
+       Msg.Msg.msgFlags = 0;
+       Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
        Msg.Msg.msgLength = sizeof(Msg);
        Msg.Data[0] = fep->frequency;
        Msg.Data[2] = 12000000;
@@ -307,24 +427,6 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
        default: return -EINVAL;
        }
 
-       /* Disable LNA, if any. An error is returned if no LNA is present */
-       ret = sms_board_lna_control(client->coredev, 0);
-       if (ret == 0) {
-               fe_status_t status;
-
-               /* tune with LNA off at first */
-               ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-                                                 &client->tune_done);
-
-               smsdvb_read_status(fe, &status);
-
-               if (status & FE_HAS_LOCK)
-                       return ret;
-
-               /* previous tune didnt lock - enable LNA and tune again */
-               sms_board_lna_control(client->coredev, 1);
-       }
-
        return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
                                           &client->tune_done);
 }
@@ -349,8 +451,7 @@ static int smsdvb_init(struct dvb_frontend *fe)
        struct smsdvb_client_t *client =
                container_of(fe, struct smsdvb_client_t, frontend);
 
-       sms_board_power(client->coredev, 1);
-
+       sms_board_dvb3_event(client, DVB3_EVENT_INIT);
        return 0;
 }
 
@@ -359,8 +460,7 @@ static int smsdvb_sleep(struct dvb_frontend *fe)
        struct smsdvb_client_t *client =
                container_of(fe, struct smsdvb_client_t, frontend);
 
-       sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-       sms_board_power(client->coredev, 0);
+       sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
 
        return 0;
 }
@@ -485,7 +585,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
        client->coredev = coredev;
 
        init_completion(&client->tune_done);
-       init_completion(&client->stat_done);
 
        kmutex_lock(&g_smsdvb_clientslock);
 
@@ -493,8 +592,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
 
        kmutex_unlock(&g_smsdvb_clientslock);
 
-       sms_info("success");
+       client->event_fe_state = -1;
+       client->event_unc_state = -1;
+       sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
 
+       sms_info("success");
        sms_board_setup(coredev);
 
        return 0;
@@ -547,5 +649,5 @@ module_init(smsdvb_module_init);
 module_exit(smsdvb_module_exit);
 
 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
-MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smsendian.c b/drivers/media/dvb/siano/smsendian.c
new file mode 100644 (file)
index 0000000..457b6d0
--- /dev/null
@@ -0,0 +1,102 @@
+/****************************************************************
+
+ Siano Mobile Silicon, Inc.
+ MDTV receiver kernel modules.
+ Copyright (C) 2006-2009, Uri Shkolnik
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ ****************************************************************/
+
+#include <asm/byteorder.h>
+
+#include "smsendian.h"
+#include "smscoreapi.h"
+
+void smsendian_handle_tx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+       struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+       int i;
+       int msgWords;
+
+       switch (msg->xMsgHeader.msgType) {
+       case MSG_SMS_DATA_DOWNLOAD_REQ:
+       {
+               msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
+               break;
+       }
+
+       default:
+               msgWords = (msg->xMsgHeader.msgLength -
+                               sizeof(struct SmsMsgHdr_ST))/4;
+
+               for (i = 0; i < msgWords; i++)
+                       msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+               break;
+       }
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
+
+void smsendian_handle_rx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+       struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+       int i;
+       int msgWords;
+
+       switch (msg->xMsgHeader.msgType) {
+       case MSG_SMS_GET_VERSION_EX_RES:
+       {
+               struct SmsVersionRes_ST *ver =
+                       (struct SmsVersionRes_ST *) msg;
+               ver->ChipModel = le16_to_cpu(ver->ChipModel);
+               break;
+       }
+
+       case MSG_SMS_DVBT_BDA_DATA:
+       case MSG_SMS_DAB_CHANNEL:
+       case MSG_SMS_DATA_MSG:
+       {
+               break;
+       }
+
+       default:
+       {
+               msgWords = (msg->xMsgHeader.msgLength -
+                               sizeof(struct SmsMsgHdr_ST))/4;
+
+               for (i = 0; i < msgWords; i++)
+                       msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+               break;
+       }
+       }
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
+
+void smsendian_handle_message_header(void *msg)
+{
+#ifdef __BIG_ENDIAN
+       struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
+
+       phdr->msgType = le16_to_cpu(phdr->msgType);
+       phdr->msgLength = le16_to_cpu(phdr->msgLength);
+       phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_message_header);
diff --git a/drivers/media/dvb/siano/smsendian.h b/drivers/media/dvb/siano/smsendian.h
new file mode 100644 (file)
index 0000000..1624d6f
--- /dev/null
@@ -0,0 +1,32 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2009, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_ENDIAN_H__
+#define __SMS_ENDIAN_H__
+
+#include <asm/byteorder.h>
+
+extern void smsendian_handle_tx_message(void *buffer);
+extern void smsendian_handle_rx_message(void *buffer);
+extern void smsendian_handle_message_header(void *msg);
+
+#endif /* __SMS_ENDIAN_H__ */
+
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
new file mode 100644 (file)
index 0000000..e3d776f
--- /dev/null
@@ -0,0 +1,301 @@
+/****************************************************************
+
+ Siano Mobile Silicon, Inc.
+ MDTV receiver kernel modules.
+ Copyright (C) 2006-2009, Uri Shkolnik
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ ****************************************************************/
+
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+#include "smscoreapi.h"
+#include "smsir.h"
+#include "sms-cards.h"
+
+/* In order to add new IR remote control -
+ * 1) Add it to the <enum ir_kb_type> @ smsir,h,
+ * 2) Add its map to keyboard_layout_maps below
+ * 3) Set your board (sms-cards sub-module) to use it
+ */
+
+static struct keyboard_layout_map_t keyboard_layout_maps[] = {
+               [SMS_IR_KB_DEFAULT_TV] = {
+                       .ir_protocol = IR_RC5,
+                       .rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
+                       .keyboard_layout_map = {
+                                       KEY_0, KEY_1, KEY_2,
+                                       KEY_3, KEY_4, KEY_5,
+                                       KEY_6, KEY_7, KEY_8,
+                                       KEY_9, 0, 0, KEY_POWER,
+                                       KEY_MUTE, 0, 0,
+                                       KEY_VOLUMEUP, KEY_VOLUMEDOWN,
+                                       KEY_BRIGHTNESSUP,
+                                       KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
+                                       KEY_CHANNELDOWN,
+                                       0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+                       }
+               },
+               [SMS_IR_KB_HCW_SILVER] = {
+                       .ir_protocol = IR_RC5,
+                       .rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
+                       .keyboard_layout_map = {
+                                       KEY_0, KEY_1, KEY_2,
+                                       KEY_3, KEY_4, KEY_5,
+                                       KEY_6, KEY_7, KEY_8,
+                                       KEY_9, KEY_TEXT, KEY_RED,
+                                       KEY_RADIO, KEY_MENU,
+                                       KEY_SUBTITLE,
+                                       KEY_MUTE, KEY_VOLUMEUP,
+                                       KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
+                                       KEY_UP, KEY_DOWN, KEY_LEFT,
+                                       KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
+                                       KEY_MHP, KEY_EPG, KEY_TV,
+                                       0, KEY_NEXTSONG, KEY_EXIT,
+                                       KEY_CHANNELUP,  KEY_CHANNELDOWN,
+                                       KEY_CHANNEL, 0,
+                                       KEY_PREVIOUSSONG, KEY_ENTER,
+                                       KEY_SLEEP, 0, 0, KEY_BLUE,
+                                       0, 0, 0, 0, KEY_GREEN, 0,
+                                       KEY_PAUSE, 0, KEY_REWIND,
+                                       0, KEY_FASTFORWARD, KEY_PLAY,
+                                       KEY_STOP, KEY_RECORD,
+                                       KEY_YELLOW, 0, 0, KEY_SELECT,
+                                       KEY_ZOOM, KEY_POWER, 0, 0
+                       }
+               },
+               { } /* Terminating entry */
+};
+
+u32 ir_pos;
+u32    ir_word;
+u32 ir_toggle;
+
+#define RC5_PUSH_BIT(dst, bit, pos)    \
+       { dst <<= 1; dst |= bit; pos++; }
+
+
+static void sms_ir_rc5_event(struct smscore_device_t *coredev,
+                               u32 toggle, u32 addr, u32 cmd)
+{
+       bool toggle_changed;
+       u16 keycode;
+
+       sms_log("IR RC5 word: address %d, command %d, toggle %d",
+                               addr, cmd, toggle);
+
+       toggle_changed = ir_toggle != toggle;
+       /* keep toggle */
+       ir_toggle = toggle;
+
+       if (addr !=
+               keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
+               return; /* Check for valid address */
+
+       keycode =
+               keyboard_layout_maps
+               [coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
+
+       if (!toggle_changed &&
+                       (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
+               return; /* accept only repeated volume, reject other keys */
+
+       sms_log("kernel input keycode (from ir) %d", keycode);
+       input_report_key(coredev->ir.input_dev, keycode, 1);
+       input_sync(coredev->ir.input_dev);
+
+}
+
+/* decode raw bit pattern to RC5 code */
+/* taken from ir-functions.c */
+static u32 ir_rc5_decode(unsigned int code)
+{
+/*     unsigned int org_code = code;*/
+       unsigned int pair;
+       unsigned int rc5 = 0;
+       int i;
+
+       for (i = 0; i < 14; ++i) {
+               pair = code & 0x3;
+               code >>= 2;
+
+               rc5 <<= 1;
+               switch (pair) {
+               case 0:
+               case 2:
+                       break;
+               case 1:
+                       rc5 |= 1;
+                       break;
+               case 3:
+/*     dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
+                       sms_log("bad code");
+                       return 0;
+               }
+       }
+/*
+       dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
+               toggle=%x, address=%x, "
+               "instr=%x\n", rc5, org_code, RC5_START(rc5),
+               RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+*/
+       return rc5;
+}
+
+static void sms_rc5_parse_word(struct smscore_device_t *coredev)
+{
+       #define RC5_START(x)    (((x)>>12)&3)
+       #define RC5_TOGGLE(x)   (((x)>>11)&1)
+       #define RC5_ADDR(x)     (((x)>>6)&0x1F)
+       #define RC5_INSTR(x)    ((x)&0x3F)
+
+       int i, j;
+       u32 rc5_word = 0;
+
+       /* Reverse the IR word direction */
+       for (i = 0 ; i < 28 ; i++)
+               RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
+
+       rc5_word = ir_rc5_decode(rc5_word);
+       /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
+
+       sms_ir_rc5_event(coredev,
+                               RC5_TOGGLE(rc5_word),
+                               RC5_ADDR(rc5_word),
+                               RC5_INSTR(rc5_word));
+}
+
+
+static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
+               s32 ir_sample)
+{
+       #define RC5_TIME_GRANULARITY    200
+       #define RC5_DEF_BIT_TIME                889
+       #define RC5_MAX_SAME_BIT_CONT   4
+       #define RC5_WORD_LEN                    27 /* 28 bit */
+
+       u32 i, j;
+       s32 delta_time;
+       u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
+       u32 level = (ir_sample < 0) ? 0 : 1;
+
+       for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
+               delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
+               if (delta_time < 0)
+                       continue; /* not so many consecutive bits */
+               if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
+                       /* timeout */
+                       if (ir_pos == (RC5_WORD_LEN-1))
+                               /* complete last bit */
+                               RC5_PUSH_BIT(ir_word, level, ir_pos)
+
+                       if (ir_pos == RC5_WORD_LEN)
+                               sms_rc5_parse_word(coredev);
+                       else if (ir_pos) /* timeout within a word */
+                               sms_log("IR error parsing a word");
+
+                       ir_pos = 0;
+                       ir_word = 0;
+                       /* sms_log("timeout %d", time); */
+                       break;
+               }
+               /* The time is within the range of this number of bits */
+               for (j = 0 ; j < i ; j++)
+                       RC5_PUSH_BIT(ir_word, level, ir_pos)
+
+               break;
+       }
+}
+
+void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
+{
+       #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
+       u32 i;
+       enum ir_protocol ir_protocol =
+                       keyboard_layout_maps[coredev->ir.ir_kb_type]
+                                            .ir_protocol;
+       s32 *samples;
+       int count = len>>2;
+
+       samples = (s32 *)buf;
+/*     sms_log("IR buffer received, length = %d", count);*/
+
+       for (i = 0; i < count; i++)
+               if (ir_protocol == IR_RC5)
+                       sms_rc5_accumulate_bits(coredev, samples[i]);
+       /*  IR_RCMM not implemented */
+}
+
+int sms_ir_init(struct smscore_device_t *coredev)
+{
+       struct input_dev *input_dev;
+
+       sms_log("Allocating input device");
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               sms_err("Not enough memory");
+               return -ENOMEM;
+       }
+
+       coredev->ir.input_dev = input_dev;
+       coredev->ir.ir_kb_type =
+               sms_get_board(smscore_get_board_id(coredev))->ir_kb_type;
+       coredev->ir.keyboard_layout_map =
+               keyboard_layout_maps[coredev->ir.ir_kb_type].
+                               keyboard_layout_map;
+       sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
+
+       coredev->ir.controller = 0;     /* Todo: vega/nova SPI number */
+       coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
+       sms_log("IR port %d, timeout %d ms",
+                       coredev->ir.controller, coredev->ir.timeout);
+
+       snprintf(coredev->ir.name,
+                               IR_DEV_NAME_MAX_LEN,
+                               "SMS IR w/kbd type %d",
+                               coredev->ir.ir_kb_type);
+       input_dev->name = coredev->ir.name;
+       input_dev->phys = coredev->ir.name;
+       input_dev->dev.parent = coredev->device;
+
+       /* Key press events only */
+       input_dev->evbit[0] = BIT_MASK(EV_KEY);
+       input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+
+       sms_log("Input device (IR) %s is set for key events", input_dev->name);
+
+       if (input_register_device(input_dev)) {
+               sms_err("Failed to register device");
+               input_free_device(input_dev);
+               return -EACCES;
+       }
+
+       return 0;
+}
+
+void sms_ir_exit(struct smscore_device_t *coredev)
+{
+       if (coredev->ir.input_dev)
+               input_unregister_device(coredev->ir.input_dev);
+
+       sms_log("");
+}
+
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
new file mode 100644 (file)
index 0000000..b7d703e
--- /dev/null
@@ -0,0 +1,93 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2009, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_IR_H__
+#define __SMS_IR_H__
+
+#include <linux/input.h>
+
+#define IR_DEV_NAME_MAX_LEN            23 /* "SMS IR kbd type nn\0" */
+#define IR_KEYBOARD_LAYOUT_SIZE        64
+#define IR_DEFAULT_TIMEOUT             100
+
+enum ir_kb_type {
+       SMS_IR_KB_DEFAULT_TV,
+       SMS_IR_KB_HCW_SILVER
+};
+
+enum rc5_keyboard_address {
+       KEYBOARD_ADDRESS_TV1 = 0,
+       KEYBOARD_ADDRESS_TV2 = 1,
+       KEYBOARD_ADDRESS_TELETEXT = 2,
+       KEYBOARD_ADDRESS_VIDEO = 3,
+       KEYBOARD_ADDRESS_LV1 = 4,
+       KEYBOARD_ADDRESS_VCR1 = 5,
+       KEYBOARD_ADDRESS_VCR2 = 6,
+       KEYBOARD_ADDRESS_EXPERIMENTAL = 7,
+       KEYBOARD_ADDRESS_SAT1 = 8,
+       KEYBOARD_ADDRESS_CAMERA = 9,
+       KEYBOARD_ADDRESS_SAT2 = 10,
+       KEYBOARD_ADDRESS_CDV = 12,
+       KEYBOARD_ADDRESS_CAMCORDER = 13,
+       KEYBOARD_ADDRESS_PRE_AMP = 16,
+       KEYBOARD_ADDRESS_TUNER = 17,
+       KEYBOARD_ADDRESS_RECORDER1 = 18,
+       KEYBOARD_ADDRESS_PRE_AMP1 = 19,
+       KEYBOARD_ADDRESS_CD_PLAYER = 20,
+       KEYBOARD_ADDRESS_PHONO = 21,
+       KEYBOARD_ADDRESS_SATA = 22,
+       KEYBOARD_ADDRESS_RECORDER2 = 23,
+       KEYBOARD_ADDRESS_CDR = 26,
+       KEYBOARD_ADDRESS_LIGHTING = 29,
+       KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */
+       KEYBOARD_ADDRESS_PHONE = 31,
+       KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF
+};
+
+enum ir_protocol {
+       IR_RC5,
+       IR_RCMM
+};
+
+struct keyboard_layout_map_t {
+       enum ir_protocol ir_protocol;
+       enum rc5_keyboard_address rc5_kbd_address;
+       u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE];
+};
+
+struct smscore_device_t;
+
+struct ir_t {
+       struct input_dev *input_dev;
+       enum ir_kb_type ir_kb_type;
+       char name[IR_DEV_NAME_MAX_LEN+1];
+       u16 *keyboard_layout_map;
+       u32 timeout;
+       u32 controller;
+};
+
+int sms_ir_init(struct smscore_device_t *coredev);
+void sms_ir_exit(struct smscore_device_t *coredev);
+void sms_ir_event(struct smscore_device_t *coredev,
+                       const char *buf, int len);
+
+#endif /* __SMS_IR_H__ */
+
diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c
new file mode 100644 (file)
index 0000000..dfaa49a
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ *  smssdio.c - Siano 1xxx SDIO interface driver
+ *
+ *  Copyright 2008 Pierre Ossman
+ *
+ * Based on code by Siano Mobile Silicon, Inc.,
+ * Copyright (C) 2006-2008, Uri Shkolnik
+ *
+ * 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 hardware is a bit odd in that all transfers should be done
+ * to/from the SMSSDIO_DATA register, yet the "increase address" bit
+ * always needs to be set.
+ *
+ * Also, buffers from the card are always aligned to 128 byte
+ * boundaries.
+ */
+
+/*
+ * General cleanup notes:
+ *
+ * - only typedefs should be name *_t
+ *
+ * - use ERR_PTR and friends for smscore_register_device()
+ *
+ * - smscore_getbuffer should zero fields
+ *
+ * Fix stop command
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+/* Registers */
+
+#define SMSSDIO_DATA           0x00
+#define SMSSDIO_INT            0x04
+
+static const struct sdio_device_id smssdio_ids[] = {
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
+        .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
+        .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
+        .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
+        .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
+        .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
+       { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, smssdio_ids);
+
+struct smssdio_device {
+       struct sdio_func *func;
+
+       struct smscore_device_t *coredev;
+
+       struct smscore_buffer_t *split_cb;
+};
+
+/*******************************************************************/
+/* Siano core callbacks                                            */
+/*******************************************************************/
+
+static int smssdio_sendrequest(void *context, void *buffer, size_t size)
+{
+       int ret;
+       struct smssdio_device *smsdev;
+
+       smsdev = context;
+
+       sdio_claim_host(smsdev->func);
+
+       while (size >= smsdev->func->cur_blksize) {
+               ret = sdio_write_blocks(smsdev->func, SMSSDIO_DATA, buffer, 1);
+               if (ret)
+                       goto out;
+
+               buffer += smsdev->func->cur_blksize;
+               size -= smsdev->func->cur_blksize;
+       }
+
+       if (size) {
+               ret = sdio_write_bytes(smsdev->func, SMSSDIO_DATA,
+                                      buffer, size);
+       }
+
+out:
+       sdio_release_host(smsdev->func);
+
+       return ret;
+}
+
+/*******************************************************************/
+/* SDIO callbacks                                                  */
+/*******************************************************************/
+
+static void smssdio_interrupt(struct sdio_func *func)
+{
+       int ret, isr;
+
+       struct smssdio_device *smsdev;
+       struct smscore_buffer_t *cb;
+       struct SmsMsgHdr_ST *hdr;
+       size_t size;
+
+       smsdev = sdio_get_drvdata(func);
+
+       /*
+        * The interrupt register has no defined meaning. It is just
+        * a way of turning of the level triggered interrupt.
+        */
+       isr = sdio_readb(func, SMSSDIO_INT, &ret);
+       if (ret) {
+               dev_err(&smsdev->func->dev,
+                       "Unable to read interrupt register!\n");
+               return;
+       }
+
+       if (smsdev->split_cb == NULL) {
+               cb = smscore_getbuffer(smsdev->coredev);
+               if (!cb) {
+                       dev_err(&smsdev->func->dev,
+                               "Unable to allocate data buffer!\n");
+                       return;
+               }
+
+               ret = sdio_read_blocks(smsdev->func, cb->p, SMSSDIO_DATA, 1);
+               if (ret) {
+                       dev_err(&smsdev->func->dev,
+                               "Error %d reading initial block!\n", ret);
+                       return;
+               }
+
+               hdr = cb->p;
+
+               if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) {
+                       smsdev->split_cb = cb;
+                       return;
+               }
+
+               size = hdr->msgLength - smsdev->func->cur_blksize;
+       } else {
+               cb = smsdev->split_cb;
+               hdr = cb->p;
+
+               size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST);
+
+               smsdev->split_cb = NULL;
+       }
+
+       if (hdr->msgLength > smsdev->func->cur_blksize) {
+               void *buffer;
+
+               size = ALIGN(size, 128);
+               buffer = cb->p + hdr->msgLength;
+
+               BUG_ON(smsdev->func->cur_blksize != 128);
+
+               /*
+                * First attempt to transfer all of it in one go...
+                */
+               ret = sdio_read_blocks(smsdev->func, buffer,
+                                      SMSSDIO_DATA, size / 128);
+               if (ret && ret != -EINVAL) {
+                       smscore_putbuffer(smsdev->coredev, cb);
+                       dev_err(&smsdev->func->dev,
+                               "Error %d reading data from card!\n", ret);
+                       return;
+               }
+
+               /*
+                * ..then fall back to one block at a time if that is
+                * not possible...
+                *
+                * (we have to do this manually because of the
+                * problem with the "increase address" bit)
+                */
+               if (ret == -EINVAL) {
+                       while (size) {
+                               ret = sdio_read_blocks(smsdev->func,
+                                                      buffer, SMSSDIO_DATA, 1);
+                               if (ret) {
+                                       smscore_putbuffer(smsdev->coredev, cb);
+                                       dev_err(&smsdev->func->dev,
+                                               "Error %d reading "
+                                               "data from card!\n", ret);
+                                       return;
+                               }
+
+                               buffer += smsdev->func->cur_blksize;
+                               if (size > smsdev->func->cur_blksize)
+                                       size -= smsdev->func->cur_blksize;
+                               else
+                                       size = 0;
+                       }
+               }
+       }
+
+       cb->size = hdr->msgLength;
+       cb->offset = 0;
+
+       smscore_onresponse(smsdev->coredev, cb);
+}
+
+static int smssdio_probe(struct sdio_func *func,
+                        const struct sdio_device_id *id)
+{
+       int ret;
+
+       int board_id;
+       struct smssdio_device *smsdev;
+       struct smsdevice_params_t params;
+
+       board_id = id->driver_data;
+
+       smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
+       if (!smsdev)
+               return -ENOMEM;
+
+       smsdev->func = func;
+
+       memset(&params, 0, sizeof(struct smsdevice_params_t));
+
+       params.device = &func->dev;
+       params.buffer_size = 0x5000;    /* ?? */
+       params.num_buffers = 22;        /* ?? */
+       params.context = smsdev;
+
+       snprintf(params.devpath, sizeof(params.devpath),
+                "sdio\\%s", sdio_func_id(func));
+
+       params.sendrequest_handler = smssdio_sendrequest;
+
+       params.device_type = sms_get_board(board_id)->type;
+
+       if (params.device_type != SMS_STELLAR)
+               params.flags |= SMS_DEVICE_FAMILY2;
+       else {
+               /*
+                * FIXME: Stellar needs special handling...
+                */
+               ret = -ENODEV;
+               goto free;
+       }
+
+       ret = smscore_register_device(&params, &smsdev->coredev);
+       if (ret < 0)
+               goto free;
+
+       smscore_set_board_id(smsdev->coredev, board_id);
+
+       sdio_claim_host(func);
+
+       ret = sdio_enable_func(func);
+       if (ret)
+               goto release;
+
+       ret = sdio_set_block_size(func, 128);
+       if (ret)
+               goto disable;
+
+       ret = sdio_claim_irq(func, smssdio_interrupt);
+       if (ret)
+               goto disable;
+
+       sdio_set_drvdata(func, smsdev);
+
+       sdio_release_host(func);
+
+       ret = smscore_start_device(smsdev->coredev);
+       if (ret < 0)
+               goto reclaim;
+
+       return 0;
+
+reclaim:
+       sdio_claim_host(func);
+       sdio_release_irq(func);
+disable:
+       sdio_disable_func(func);
+release:
+       sdio_release_host(func);
+       smscore_unregister_device(smsdev->coredev);
+free:
+       kfree(smsdev);
+
+       return ret;
+}
+
+static void smssdio_remove(struct sdio_func *func)
+{
+       struct smssdio_device *smsdev;
+
+       smsdev = sdio_get_drvdata(func);
+
+       /* FIXME: racy! */
+       if (smsdev->split_cb)
+               smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
+
+       smscore_unregister_device(smsdev->coredev);
+
+       sdio_claim_host(func);
+       sdio_release_irq(func);
+       sdio_disable_func(func);
+       sdio_release_host(func);
+
+       kfree(smsdev);
+}
+
+static struct sdio_driver smssdio_driver = {
+       .name = "smssdio",
+       .id_table = smssdio_ids,
+       .probe = smssdio_probe,
+       .remove = smssdio_remove,
+};
+
+/*******************************************************************/
+/* Module functions                                                */
+/*******************************************************************/
+
+int smssdio_module_init(void)
+{
+       int ret = 0;
+
+       printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
+       printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
+
+       ret = sdio_register_driver(&smssdio_driver);
+
+       return ret;
+}
+
+void smssdio_module_exit(void)
+{
+       sdio_unregister_driver(&smssdio_driver);
+}
+
+module_init(smssdio_module_init);
+module_exit(smssdio_module_exit);
+
+MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
+MODULE_AUTHOR("Pierre Ossman");
+MODULE_LICENSE("GPL");
index 71c65f544c072911cb326f8614097378448e2618..cb8a358b7310d35417413a5300f62ad6a4065cff 100644 (file)
@@ -1,23 +1,23 @@
-/*
- *  Driver for the Siano SMS1xxx USB dongle
- *
- *  author: Anatoly Greenblat
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  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.
- */
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
 
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -26,6 +26,7 @@
 
 #include "smscoreapi.h"
 #include "sms-cards.h"
+#include "smsendian.h"
 
 static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
@@ -64,15 +65,16 @@ static void smsusb_onresponse(struct urb *urb)
        struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
        struct smsusb_device_t *dev = surb->dev;
 
-       if (urb->status < 0) {
-               sms_err("error, urb status %d, %d bytes",
+       if (urb->status == -ESHUTDOWN) {
+               sms_err("error, urb status %d (-ESHUTDOWN), %d bytes",
                        urb->status, urb->actual_length);
                return;
        }
 
-       if (urb->actual_length > 0) {
-               struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
+       if ((urb->actual_length > 0) && (urb->status == 0)) {
+               struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p;
 
+               smsendian_handle_message_header(phdr);
                if (urb->actual_length >= phdr->msgLength) {
                        surb->cb->size = phdr->msgLength;
 
@@ -109,7 +111,10 @@ static void smsusb_onresponse(struct urb *urb)
                                "msglen %d actual %d",
                                phdr->msgLength, urb->actual_length);
                }
-       }
+       } else
+               sms_err("error, urb status %d, %d bytes",
+                       urb->status, urb->actual_length);
+
 
 exit_and_resubmit:
        smsusb_submit_urb(dev, surb);
@@ -176,6 +181,7 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size)
        struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
        int dummy;
 
+       smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer);
        return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
                            buffer, size, &dummy, 1000);
 }
@@ -333,8 +339,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
        case SMS_VEGA:
                dev->buffer_size = USB2_BUFFER_SIZE;
                dev->response_alignment =
-                       dev->udev->ep_in[1]->desc.wMaxPacketSize -
-                       sizeof(struct SmsMsgHdr_ST);
+                   le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
+                   sizeof(struct SmsMsgHdr_ST);
 
                params.flags |= SMS_DEVICE_FAMILY2;
                break;
@@ -479,7 +485,6 @@ static int smsusb_resume(struct usb_interface *intf)
 }
 
 struct usb_device_id smsusb_id_table[] = {
-#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
        { USB_DEVICE(0x187f, 0x0010),
                .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
        { USB_DEVICE(0x187f, 0x0100),
@@ -490,7 +495,6 @@ struct usb_device_id smsusb_id_table[] = {
                .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
        { USB_DEVICE(0x187f, 0x0300),
                .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
-#endif
        { USB_DEVICE(0x2040, 0x1700),
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
        { USB_DEVICE(0x2040, 0x1800),
@@ -521,8 +525,13 @@ struct usb_device_id smsusb_id_table[] = {
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
        { USB_DEVICE(0x2040, 0x5590),
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-       { }             /* Terminating entry */
-};
+       { USB_DEVICE(0x187f, 0x0202),
+               .driver_info = SMS1XXX_BOARD_SIANO_NICE },
+       { USB_DEVICE(0x187f, 0x0301),
+               .driver_info = SMS1XXX_BOARD_SIANO_VENICE },
+       { } /* Terminating entry */
+       };
+
 MODULE_DEVICE_TABLE(usb, smsusb_id_table);
 
 static struct usb_driver smsusb_driver = {
@@ -548,14 +557,14 @@ int smsusb_module_init(void)
 
 void smsusb_module_exit(void)
 {
-       sms_debug("");
        /* Regular USB Cleanup */
        usb_deregister(&smsusb_driver);
+       sms_info("end");
 }
 
 module_init(smsusb_module_init);
 module_exit(smsusb_module_exit);
 
-MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
+MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
 MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
 MODULE_LICENSE("GPL");
index e4d0900d5121f0bfa6d343e7ac29de1fb906e542..53884814161c2a064853de36a8557b14b04aad75 100644 (file)
@@ -89,6 +89,7 @@
 
 static void p_to_t(u8 const *buf, long int length, u16 pid,
                   u8 *counter, struct dvb_demux_feed *feed);
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);
 
 
 int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
@@ -192,8 +193,6 @@ int av7110_av_start_play(struct av7110 *av7110, int av)
                ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
                break;
        }
-       if (!ret)
-               ret = av7110->playing;
        return ret;
 }
 
@@ -437,6 +436,45 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
        aux_ring_buffer_write(&av7110->aout, buf, count);
 }
 
+
+#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)
+
+static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
+                      unsigned long count, int nonblock, int type)
+{
+       struct dvb_ringbuffer *rb;
+       u8 *kb;
+       unsigned long todo = count;
+
+       dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);
+
+       rb = (type) ? &av7110->avout : &av7110->aout;
+       kb = av7110->kbuf[type];
+
+       if (!kb)
+               return -ENOBUFS;
+
+       if (nonblock && !FREE_COND_TS)
+               return -EWOULDBLOCK;
+
+       while (todo >= TS_SIZE) {
+               if (!FREE_COND_TS) {
+                       if (nonblock)
+                               return count - todo;
+                       if (wait_event_interruptible(rb->queue, FREE_COND_TS))
+                               return count - todo;
+               }
+               if (copy_from_user(kb, buf, TS_SIZE))
+                       return -EFAULT;
+               write_ts_to_decoder(av7110, type, kb, TS_SIZE);
+               todo -= TS_SIZE;
+               buf += TS_SIZE;
+       }
+
+       return count - todo;
+}
+
+
 #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
                   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
 
@@ -780,11 +818,37 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
 }
 
 
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)
+{
+       struct ipack *ipack = &av7110->ipack[type];
+
+       if (buf[1] & TRANS_ERROR) {
+               av7110_ipack_reset(ipack);
+               return -1;
+       }
+
+       if (!(buf[3] & PAYLOAD))
+               return -1;
+
+       if (buf[1] & PAY_START)
+               av7110_ipack_flush(ipack);
+
+       if (buf[3] & ADAPT_FIELD) {
+               len -= buf[4] + 1;
+               buf += buf[4] + 1;
+               if (!len)
+                       return 0;
+       }
+
+       av7110_ipack_instant_repack(buf + 4, len - 4, ipack);
+       return 0;
+}
+
+
 int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
 {
        struct dvb_demux *demux = feed->demux;
        struct av7110 *av7110 = (struct av7110 *) demux->priv;
-       struct ipack *ipack = &av7110->ipack[feed->pes_type];
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -804,20 +868,7 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l
                return -1;
        }
 
-       if (!(buf[3] & 0x10)) /* no payload? */
-               return -1;
-       if (buf[1] & 0x40)
-               av7110_ipack_flush(ipack);
-
-       if (buf[3] & 0x20) {  /* adaptation field? */
-               len -= buf[4] + 1;
-               buf += buf[4] + 1;
-               if (!len)
-                       return 0;
-       }
-
-       av7110_ipack_instant_repack(buf + 4, len - 4, &av7110->ipack[feed->pes_type]);
-       return 0;
+       return write_ts_to_decoder(av7110, feed->pes_type, buf, len);
 }
 
 
@@ -916,6 +967,7 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct av7110 *av7110 = dvbdev->priv;
+       unsigned char c;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -925,7 +977,12 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
        if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
                return -EPERM;
 
-       return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+       if (get_user(c, buf))
+               return -EFAULT;
+       if (c == 0x47 && count % TS_SIZE == 0)
+               return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+       else
+               return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
 }
 
 static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
@@ -952,6 +1009,7 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct av7110 *av7110 = dvbdev->priv;
+       unsigned char c;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -959,7 +1017,13 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
                printk(KERN_ERR "not audio source memory\n");
                return -EPERM;
        }
-       return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+
+       if (get_user(c, buf))
+               return -EFAULT;
+       if (c == 0x47 && count % TS_SIZE == 0)
+               return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+       else
+               return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
 }
 
 static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
@@ -1062,7 +1126,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
                        if (ret)
                                break;
                }
-
                if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
                        if (av7110->playing == RP_AV) {
                                ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
@@ -1122,20 +1185,16 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
        case VIDEO_SET_DISPLAY_FORMAT:
        {
                video_displayformat_t format = (video_displayformat_t) arg;
-
                switch (format) {
                case VIDEO_PAN_SCAN:
                        av7110->display_panscan = VID_PAN_SCAN_PREF;
                        break;
-
                case VIDEO_LETTER_BOX:
                        av7110->display_panscan = VID_VC_AND_PS_PREF;
                        break;
-
                case VIDEO_CENTER_CUT_OUT:
                        av7110->display_panscan = VID_CENTRE_CUT_PREF;
                        break;
-
                default:
                        ret = -EINVAL;
                }
@@ -1183,7 +1242,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
 
        case VIDEO_SLOWMOTION:
                if (av7110->playing&RP_VIDEO) {
-                       ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
+                       if (av7110->trickmode != TRICK_SLOW)
+                               ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
                        if (!ret)
                                ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
                } else {
@@ -1207,7 +1267,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
        case VIDEO_CLEAR_BUFFER:
                dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
                av7110_ipack_reset(&av7110->ipack[1]);
-
                if (av7110->playing == RP_AV) {
                        ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
                                            __Play, 2, AV_PES, 0);
@@ -1228,13 +1287,13 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
                break;
 
        case VIDEO_SET_STREAMTYPE:
-
                break;
 
        default:
                ret = -ENOIOCTLCMD;
                break;
        }
+
        return ret;
 }
 
@@ -1309,7 +1368,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 
        case AUDIO_CHANNEL_SELECT:
                av7110->audiostate.channel_select = (audio_channel_select_t) arg;
-
                switch(av7110->audiostate.channel_select) {
                case AUDIO_STEREO:
                        ret = audcom(av7110, AUDIO_CMD_STEREO);
@@ -1320,7 +1378,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                                        msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
                        }
                        break;
-
                case AUDIO_MONO_LEFT:
                        ret = audcom(av7110, AUDIO_CMD_MONO_L);
                        if (!ret) {
@@ -1330,7 +1387,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                                        msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
                        }
                        break;
-
                case AUDIO_MONO_RIGHT:
                        ret = audcom(av7110, AUDIO_CMD_MONO_R);
                        if (!ret) {
@@ -1340,7 +1396,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                                        msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
                        }
                        break;
-
                default:
                        ret = -EINVAL;
                        break;
@@ -1366,21 +1421,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                        ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
                                            __Play, 2, AV_PES, 0);
                break;
-       case AUDIO_SET_ID:
 
+       case AUDIO_SET_ID:
                break;
+
        case AUDIO_SET_MIXER:
        {
                struct audio_mixer *amix = (struct audio_mixer *)parg;
-
                ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
                break;
        }
+
        case AUDIO_SET_STREAMTYPE:
                break;
+
        default:
                ret = -ENOIOCTLCMD;
        }
+
        return ret;
 }
 
index 5e3f88911a1d2503c1a2dfd3e5ea8b2c8275cead..e162691b515d14d0213c59d624fbb2b95cefff7d 100644 (file)
@@ -1089,7 +1089,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
                else {
                        int i, len = dc->x0-dc->color+1;
                        u8 __user *colors = (u8 __user *)dc->data;
-                       u8 r, g, b, blend;
+                       u8 r, g = 0, b = 0, blend = 0;
                        ret = 0;
                        for (i = 0; i<len; i++) {
                                if (get_user(r, colors + i * 4) ||
index 2210cff738e67a7e47a26d29faddb18633ba0ee1..ce64c6214cc410d473e61eac226ffa3514acea19 100644 (file)
@@ -458,7 +458,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
        dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
 
        if (av7110->analog_tuner_flags) {
-               if (i->index < 0 || i->index >= 4)
+               if (i->index >= 4)
                        return -EINVAL;
        } else {
                if (i->index != 0)
index 855fe74b640bc85d3c5b1ab69936d8f3b3be0a36..8ea9152276744ade58813141ceb91ad121da26dc 100644 (file)
@@ -1413,7 +1413,7 @@ static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
        dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
-       if (i->index < 0 || i->index >= KNC1_INPUTS)
+       if (i->index >= KNC1_INPUTS)
                return -EINVAL;
        memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
        return 0;
index 83e9e7750c8cb1e382ddda99e901f7fef1514d48..e48380c48990165955a9dadeb80d90a758aa6e46 100644 (file)
@@ -47,6 +47,9 @@
 #include "bsru6.h"
 #include "bsbe1.h"
 #include "tdhd1.h"
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "isl6423.h"
 
 static int diseqc_method;
 module_param(diseqc_method, int, 0444);
@@ -425,6 +428,44 @@ static u8 read_pwm(struct budget* budget)
        return pwm;
 }
 
+static struct stv090x_config tt1600_stv090x_config = {
+       .device                 = STV0903,
+       .demod_mode             = STV090x_SINGLE,
+       .clk_mode               = STV090x_CLK_EXT,
+
+       .xtal                   = 27000000,
+       .address                = 0x68,
+       .ref_clk                = 27000000,
+
+       .ts1_mode               = STV090x_TSMODE_DVBCI,
+       .ts2_mode               = STV090x_TSMODE_SERIAL_CONTINUOUS,
+
+       .repeater_level         = STV090x_RPTLEVEL_16,
+
+       .tuner_init             = NULL,
+       .tuner_set_mode         = NULL,
+       .tuner_set_frequency    = NULL,
+       .tuner_get_frequency    = NULL,
+       .tuner_set_bandwidth    = NULL,
+       .tuner_get_bandwidth    = NULL,
+       .tuner_set_bbgain       = NULL,
+       .tuner_get_bbgain       = NULL,
+       .tuner_set_refclk       = NULL,
+       .tuner_get_status       = NULL,
+};
+
+static struct stv6110x_config tt1600_stv6110x_config = {
+       .addr                   = 0x60,
+       .refclk                 = 27000000,
+};
+
+static struct isl6423_config tt1600_isl6423_config = {
+       .current_max            = SEC_CURRENT_515m,
+       .curlim                 = SEC_CURRENT_LIM_ON,
+       .mod_extern             = 1,
+       .addr                   = 0x08,
+};
+
 static void frontend_init(struct budget *budget)
 {
        (void)alps_bsbe1_config; /* avoid warning */
@@ -566,6 +607,48 @@ static void frontend_init(struct budget *budget)
                        }
                        break;
                }
+
+       case 0x101c: { /* TT S2-1600 */
+                       struct stv6110x_devctl *ctl;
+                       saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+                       msleep(50);
+                       saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+                       msleep(250);
+
+                       budget->dvb_frontend = dvb_attach(stv090x_attach,
+                                                         &tt1600_stv090x_config,
+                                                         &budget->i2c_adap,
+                                                         STV090x_DEMODULATOR_0);
+
+                       if (budget->dvb_frontend) {
+
+                               ctl = dvb_attach(stv6110x_attach,
+                                                budget->dvb_frontend,
+                                                &tt1600_stv6110x_config,
+                                                &budget->i2c_adap);
+
+                               tt1600_stv090x_config.tuner_init          = ctl->tuner_init;
+                               tt1600_stv090x_config.tuner_set_mode      = ctl->tuner_set_mode;
+                               tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+                               tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+                               tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+                               tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+                               tt1600_stv090x_config.tuner_set_bbgain    = ctl->tuner_set_bbgain;
+                               tt1600_stv090x_config.tuner_get_bbgain    = ctl->tuner_get_bbgain;
+                               tt1600_stv090x_config.tuner_set_refclk    = ctl->tuner_set_refclk;
+                               tt1600_stv090x_config.tuner_get_status    = ctl->tuner_get_status;
+
+                               dvb_attach(isl6423_attach,
+                                       budget->dvb_frontend,
+                                       &budget->i2c_adap,
+                                       &tt1600_isl6423_config);
+
+                       } else {
+                               dvb_frontend_detach(budget->dvb_frontend);
+                               budget->dvb_frontend = NULL;
+                       }
+               }
+               break;
        }
 
        if (budget->dvb_frontend == NULL) {
@@ -641,6 +724,7 @@ MAKE_BUDGET_INFO(ttbc,      "TT-Budget/WinTV-NOVA-C  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(satel,        "SATELCO Multimedia PCI",       BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsact,         "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
@@ -653,6 +737,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
        MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
        MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
+       MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),
        MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
        MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
        MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
index 6135762022940ec4095538bfa446803fb2be6373..ed9cd7ad06042c630ec147e6a3b830a5a2e3904f 100644 (file)
 
  History:
 
+ Version 0.46:
+       Removed usb_dsbr100_open/close calls and radio->users counter. Also,
+       radio->muted changed to radio->status and suspend/resume calls updated.
+
  Version 0.45:
        Converted to v4l2_device.
 
  */
 #include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
 
-#define DRIVER_VERSION "v0.45"
-#define RADIO_VERSION KERNEL_VERSION(0, 4, 5)
+#define DRIVER_VERSION "v0.46"
+#define RADIO_VERSION KERNEL_VERSION(0, 4, 6)
 
 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@@ -121,13 +125,15 @@ devices, that would be 76 and 91.  */
 #define FREQ_MAX 108.0
 #define FREQ_MUL 16000
 
+/* defines for radio->status */
+#define STARTED        0
+#define STOPPED        1
+
 #define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
 
 static int usb_dsbr100_probe(struct usb_interface *intf,
                             const struct usb_device_id *id);
 static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_open(struct file *file);
-static int usb_dsbr100_close(struct file *file);
 static int usb_dsbr100_suspend(struct usb_interface *intf,
                                                pm_message_t message);
 static int usb_dsbr100_resume(struct usb_interface *intf);
@@ -145,9 +151,8 @@ struct dsbr100_device {
        struct mutex lock;      /* buffer locking */
        int curfreq;
        int stereo;
-       int users;
        int removed;
-       int muted;
+       int status;
 };
 
 static struct usb_device_id usb_dsbr100_device_table [] = {
@@ -201,7 +206,7 @@ static int dsbr100_start(struct dsbr100_device *radio)
                goto usb_control_msg_failed;
        }
 
-       radio->muted = 0;
+       radio->status = STARTED;
        mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
 
@@ -244,7 +249,7 @@ static int dsbr100_stop(struct dsbr100_device *radio)
                goto usb_control_msg_failed;
        }
 
-       radio->muted = 1;
+       radio->status = STOPPED;
        mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
 
@@ -258,12 +263,12 @@ usb_control_msg_failed:
 }
 
 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
+static int dsbr100_setfreq(struct dsbr100_device *radio)
 {
        int retval;
        int request;
+       int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
 
-       freq = (freq / 16 * 80) / 1000 + 856;
        mutex_lock(&radio->lock);
 
        retval = usb_control_msg(radio->usbdev,
@@ -431,7 +436,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        radio->curfreq = f->frequency;
        mutex_unlock(&radio->lock);
 
-       retval = dsbr100_setfreq(radio, radio->curfreq);
+       retval = dsbr100_setfreq(radio);
        if (retval < 0)
                dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
        return 0;
@@ -473,7 +478,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = radio->muted;
+               ctrl->value = radio->status;
                return 0;
        }
        return -EINVAL;
@@ -543,65 +548,27 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return 0;
 }
 
-static int usb_dsbr100_open(struct file *file)
-{
-       struct dsbr100_device *radio = video_drvdata(file);
-       int retval;
-
-       lock_kernel();
-       radio->users = 1;
-       radio->muted = 1;
-
-       retval = dsbr100_start(radio);
-       if (retval < 0) {
-               dev_warn(&radio->usbdev->dev,
-                        "Radio did not start up properly\n");
-               radio->users = 0;
-               unlock_kernel();
-               return -EIO;
-       }
-
-       retval = dsbr100_setfreq(radio, radio->curfreq);
-       if (retval < 0)
-               dev_warn(&radio->usbdev->dev,
-                       "set frequency failed\n");
-
-       unlock_kernel();
-       return 0;
-}
-
-static int usb_dsbr100_close(struct file *file)
-{
-       struct dsbr100_device *radio = video_drvdata(file);
-       int retval;
-
-       if (!radio)
-               return -ENODEV;
-
-       mutex_lock(&radio->lock);
-       radio->users = 0;
-       mutex_unlock(&radio->lock);
-
-       if (!radio->removed) {
-               retval = dsbr100_stop(radio);
-               if (retval < 0) {
-                       dev_warn(&radio->usbdev->dev,
-                               "dsbr100_stop failed\n");
-               }
-
-       }
-       return 0;
-}
-
 /* Suspend device - stop device. */
 static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct dsbr100_device *radio = usb_get_intfdata(intf);
        int retval;
 
-       retval = dsbr100_stop(radio);
-       if (retval < 0)
-               dev_warn(&intf->dev, "dsbr100_stop failed\n");
+       if (radio->status == STARTED) {
+               retval = dsbr100_stop(radio);
+               if (retval < 0)
+                       dev_warn(&intf->dev, "dsbr100_stop failed\n");
+
+               /* After dsbr100_stop() status set to STOPPED.
+                * If we want driver to start radio on resume
+                * we set status equal to STARTED.
+                * On resume we will check status and run radio if needed.
+                */
+
+               mutex_lock(&radio->lock);
+               radio->status = STARTED;
+               mutex_unlock(&radio->lock);
+       }
 
        dev_info(&intf->dev, "going into suspend..\n");
 
@@ -614,9 +581,11 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
        struct dsbr100_device *radio = usb_get_intfdata(intf);
        int retval;
 
-       retval = dsbr100_start(radio);
-       if (retval < 0)
-               dev_warn(&intf->dev, "dsbr100_start failed\n");
+       if (radio->status == STARTED) {
+               retval = dsbr100_start(radio);
+               if (retval < 0)
+                       dev_warn(&intf->dev, "dsbr100_start failed\n");
+       }
 
        dev_info(&intf->dev, "coming out of suspend..\n");
 
@@ -636,8 +605,6 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev)
 /* File system interface */
 static const struct v4l2_file_operations usb_dsbr100_fops = {
        .owner          = THIS_MODULE,
-       .open           = usb_dsbr100_open,
-       .release        = usb_dsbr100_close,
        .ioctl          = video_ioctl2,
 };
 
@@ -695,9 +662,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
        mutex_init(&radio->lock);
 
        radio->removed = 0;
-       radio->users = 0;
        radio->usbdev = interface_to_usbdev(intf);
        radio->curfreq = FREQ_MIN * FREQ_MUL;
+       radio->status = STOPPED;
 
        video_set_drvdata(&radio->videodev, radio);
 
index cab19d05e02f91567750c427c4e45dfed73463e7..837467f93805e9c2f32b37c0f71cce6d3852ffef 100644 (file)
@@ -64,6 +64,7 @@
 #include <media/v4l2-ioctl.h>
 #include <linux/usb.h>
 #include <linux/version.h>     /* for KERNEL_VERSION MACRO */
+#include <linux/mutex.h>
 
 /* driver and module definitions */
 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
index 5cf6c45b91fe4c2559d4764469cd2cf3af160ca9..49c4aab95daba17a6298a007af3ac502bb7a0282 100644 (file)
@@ -49,7 +49,6 @@ struct fmi
        int io;
        int curvol; /* 1 or 0 */
        unsigned long curfreq; /* freq in kHz */
-       __u32 flags;
        struct mutex lock;
 };
 
@@ -57,7 +56,7 @@ static struct fmi fmi_card;
 static struct pnp_dev *dev;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
-/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
+/* It is only useful to give freq in interval of 800 (=0.05Mhz),
  * other bits will be truncated, e.g 92.7400016 -> 92.7, but
  * 92.7400017 -> 92.75
  */
@@ -142,7 +141,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       int mult;
        struct fmi *fmi = video_drvdata(file);
 
        if (v->index > 0)
@@ -150,11 +148,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 
        strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
-       mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
-       v->rangelow = RSF16_MINFREQ / mult;
-       v->rangehigh = RSF16_MAXFREQ / mult;
+       v->rangelow = RSF16_MINFREQ;
+       v->rangehigh = RSF16_MAXFREQ;
        v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->capability = fmi->flags & V4L2_TUNER_CAP_LOW;
+       v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
        v->audmode = V4L2_TUNER_MODE_STEREO;
        v->signal = fmi_getsigstr(fmi);
        return 0;
@@ -171,8 +168,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
        struct fmi *fmi = video_drvdata(file);
 
-       if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
-               f->frequency *= 1000;
        if (f->frequency < RSF16_MINFREQ ||
                        f->frequency > RSF16_MAXFREQ)
                return -EINVAL;
@@ -189,8 +184,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = fmi->curfreq;
-       if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
-               f->frequency /= 1000;
        return 0;
 }
 
@@ -347,7 +340,6 @@ static int __init fmi_init(void)
                return res;
        }
 
-       fmi->flags = V4L2_TUNER_CAP_LOW;
        strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
        fmi->vdev.v4l2_dev = v4l2_dev;
        fmi->vdev.fops = &fmi_fops;
index 935ff9bcdfcc6b4775455857bb0a2604fe3d9758..a11414f648d4f9279431b98d103450d4c8926bfd 100644 (file)
@@ -61,13 +61,12 @@ struct fmr2
        int stereo; /* card is producing stereo audio */
        unsigned long curfreq; /* freq in kHz */
        int card_type;
-       u32 flags;
 };
 
 static struct fmr2 fmr2_card;
 
 /* hw precision is 12.5 kHz
- * It is only useful to give freq in intervall of 200 (=0.0125Mhz),
+ * It is only useful to give freq in interval of 200 (=0.0125Mhz),
  * other bits will be truncated
  */
 #define RSF16_ENCODE(x)        ((x) / 200 + 856)
@@ -221,7 +220,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       int mult;
        struct fmr2 *fmr2 = video_drvdata(file);
 
        if (v->index > 0)
@@ -230,13 +228,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
 
-       mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
-       v->rangelow = RSF16_MINFREQ / mult;
-       v->rangehigh = RSF16_MAXFREQ / mult;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW;
-       v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
-                               V4L2_TUNER_MODE_MONO;
+       v->rangelow = RSF16_MINFREQ;
+       v->rangehigh = RSF16_MAXFREQ;
+       v->rxsubchans = fmr2->stereo ? V4L2_TUNER_SUB_STEREO :
+                                       V4L2_TUNER_SUB_MONO;
+       v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
+       v->audmode = V4L2_TUNER_MODE_STEREO;
        mutex_lock(&fmr2->lock);
        v->signal = fmr2_getsigstr(fmr2);
        mutex_unlock(&fmr2->lock);
@@ -254,8 +251,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
        struct fmr2 *fmr2 = video_drvdata(file);
 
-       if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
-               f->frequency *= 1000;
        if (f->frequency < RSF16_MINFREQ ||
                        f->frequency > RSF16_MAXFREQ)
                return -EINVAL;
@@ -279,8 +274,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = fmr2->curfreq;
-       if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
-               f->frequency /= 1000;
        return 0;
 }
 
@@ -406,7 +399,6 @@ static int __init fmr2_init(void)
        strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name));
        fmr2->io = io;
        fmr2->stereo = 1;
-       fmr2->flags = V4L2_TUNER_CAP_LOW;
        mutex_init(&fmr2->lock);
 
        if (!request_region(fmr2->io, 2, "sf16fmr2")) {
index bd945d04dc90cb095e9550c6572aeb32502c2792..640421ceb24a2a48918b1692367c5394c6fd7968 100644 (file)
@@ -1214,7 +1214,6 @@ static int si470x_fops_release(struct file *file)
                usb_autopm_put_interface(radio->intf);
        }
 
-unlock:
        mutex_unlock(&radio->disconnect_lock);
 
 done:
index 57835f5715fcaab55587224339e594772d477e11..94f440535c648896e9e84264ca94b9594542a243 100644 (file)
@@ -440,6 +440,24 @@ config VIDEO_ADV7175
          To compile this driver as a module, choose M here: the
          module will be called adv7175.
 
+config VIDEO_THS7303
+       tristate "THS7303 Video Amplifier"
+       depends on I2C
+       help
+         Support for TI THS7303 video amplifier
+
+         To compile this driver as a module, choose M here: the
+         module will be called ths7303.
+
+config VIDEO_ADV7343
+       tristate "ADV7343 video encoder"
+       depends on I2C
+       help
+         Support for Analog Devices I2C bus based ADV7343 encoder.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adv7343.
+
 comment "Video improvement chips"
 
 config VIDEO_UPD64031A
@@ -694,7 +712,7 @@ config VIDEO_CAFE_CCIC
 
 config SOC_CAMERA
        tristate "SoC camera support"
-       depends on VIDEO_V4L2 && HAS_DMA
+       depends on VIDEO_V4L2 && HAS_DMA && I2C
        select VIDEOBUF_GEN
        help
          SoC Camera is a common API to several cameras, not connecting
index 3f1a0350a5690a772b9c88dba113223cfca49e47..7fb3add1b387916d9729279b2e78a2a786c7505a 100644 (file)
@@ -12,6 +12,8 @@ omap2cam-objs :=      omap24xxcam.o omap24xxcam-dma.o
 
 videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o
 
+# V4L2 core modules
+
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
 ifeq ($(CONFIG_COMPAT),y)
   obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
@@ -23,21 +25,15 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
   obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
 endif
 
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+# All i2c modules must come first:
 
-obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
-
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
 obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
-obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
-obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
-obj-$(CONFIG_VIDEO_W9966) += w9966.o
-
 obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
 obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
 obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
@@ -49,16 +45,47 @@ obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
 obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
 obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
 obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
+obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
 obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
 obj-$(CONFIG_VIDEO_BT819) += bt819.o
 obj-$(CONFIG_VIDEO_BT856) += bt856.o
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
+obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
+obj-$(CONFIG_VIDEO_VINO) += indycam.o
+obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
+obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
+obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_M52790) += m52790.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
+obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
+obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
+obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_OV7670)     += ov7670.o
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
-obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
+obj-$(CONFIG_SOC_CAMERA_MT9T031)       += mt9t031.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
+obj-$(CONFIG_SOC_CAMERA_TW9910)                += tw9910.o
 
+# And now the v4l2 drivers:
+
+obj-$(CONFIG_VIDEO_BT848) += bt8xx/
+obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
+obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
+obj-$(CONFIG_VIDEO_W9966) += w9966.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o
 obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
 obj-$(CONFIG_VIDEO_CPIA) += cpia.o
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
@@ -69,17 +96,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
-obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
-obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
-obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
-obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
-obj-$(CONFIG_VIDEO_M52790) += m52790.o
-obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
-obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
-obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
-obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
@@ -92,19 +109,12 @@ obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
 obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
-obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
-obj-$(CONFIG_VIDEO_CX25840) += cx25840/
-obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
-obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
-obj-$(CONFIG_VIDEO_OV7670)     += ov7670.o
-
-obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
@@ -134,24 +144,21 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
+obj-$(CONFIG_VIDEO_OMAP2)              += omap2cam.o
+obj-$(CONFIG_SOC_CAMERA)               += soc_camera.o
+obj-$(CONFIG_SOC_CAMERA_PLATFORM)      += soc_camera_platform.o
+# soc-camera host drivers have to be linked after camera drivers
 obj-$(CONFIG_VIDEO_MX1)                        += mx1_camera.o
 obj-$(CONFIG_VIDEO_MX3)                        += mx3_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)             += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
-obj-$(CONFIG_VIDEO_OMAP2)              += omap2cam.o
-obj-$(CONFIG_SOC_CAMERA)               += soc_camera.o
-obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
-obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
-obj-$(CONFIG_SOC_CAMERA_MT9T031)       += mt9t031.o
-obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
-obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
-obj-$(CONFIG_SOC_CAMERA_PLATFORM)      += soc_camera_platform.o
-obj-$(CONFIG_SOC_CAMERA_TW9910)                += tw9910.o
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 
 obj-$(CONFIG_USB_VIDEO_CLASS)  += uvc/
 
+obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c
new file mode 100644 (file)
index 0000000..30f5caf
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * adv7343 - ADV7343 Video Encoder Driver
+ *
+ * The encoder hardware does not support SECAM.
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+
+#include <media/adv7343.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "adv7343_regs.h"
+
+MODULE_DESCRIPTION("ADV7343 video encoder driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+struct adv7343_state {
+       struct v4l2_subdev sd;
+       u8 reg00;
+       u8 reg01;
+       u8 reg02;
+       u8 reg35;
+       u8 reg80;
+       u8 reg82;
+       int bright;
+       int hue;
+       int gain;
+       u32 output;
+       v4l2_std_id std;
+};
+
+static inline struct adv7343_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct adv7343_state, sd);
+}
+
+static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static const u8 adv7343_init_reg_val[] = {
+       ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT,
+       ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT,
+
+       ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT,
+       ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT,
+       ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT,
+       ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT,
+       ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT,
+       ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT,
+       ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT,
+
+       ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT,
+       ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT,
+       ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT,
+       ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT,
+       ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT,
+       ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT,
+       ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT,
+       ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT,
+
+       ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT,
+       ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT,
+       ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT,
+};
+
+/*
+ *                         2^32
+ * FSC(reg) =  FSC (HZ) * --------
+ *                       27000000
+ */
+static const struct adv7343_std_info stdinfo[] = {
+       {
+               /* FSC(Hz) = 3,579,545.45 Hz */
+               SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
+       }, {
+               /* FSC(Hz) = 3,575,611.00 Hz */
+               SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
+       }, {
+               /* FSC(Hz) = 3,582,056.00 */
+               SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
+       },
+};
+
+static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct adv7343_state *state = to_state(sd);
+       struct adv7343_std_info *std_info;
+       int output_idx, num_std;
+       char *fsc_ptr;
+       u8 reg, val;
+       int err = 0;
+       int i = 0;
+
+       output_idx = state->output;
+
+       std_info = (struct adv7343_std_info *)stdinfo;
+       num_std = ARRAY_SIZE(stdinfo);
+
+       for (i = 0; i < num_std; i++) {
+               if (std_info[i].stdid & std)
+                       break;
+       }
+
+       if (i == num_std) {
+               v4l2_dbg(1, debug, sd,
+                               "Invalid std or std is not supported: %llx\n",
+                                               (unsigned long long)std);
+               return -EINVAL;
+       }
+
+       /* Set the standard */
+       val = state->reg80 & (~(SD_STD_MASK));
+       val |= std_info[i].standard_val3;
+       err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
+       if (err < 0)
+               goto setstd_exit;
+
+       state->reg80 = val;
+
+       /* Configure the input mode register */
+       val = state->reg01 & (~((u8) INPUT_MODE_MASK));
+       val |= SD_INPUT_MODE;
+       err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val);
+       if (err < 0)
+               goto setstd_exit;
+
+       state->reg01 = val;
+
+       /* Program the sub carrier frequency registers */
+       fsc_ptr = (unsigned char *)&std_info[i].fsc_val;
+       reg = ADV7343_FSC_REG0;
+       for (i = 0; i < 4; i++, reg++, fsc_ptr++) {
+               err = adv7343_write(sd, reg, *fsc_ptr);
+               if (err < 0)
+                       goto setstd_exit;
+       }
+
+       val = state->reg80;
+
+       /* Filter settings */
+       if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
+               val &= 0x03;
+       else if (std & ~V4L2_STD_SECAM)
+               val |= 0x04;
+
+       err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
+       if (err < 0)
+               goto setstd_exit;
+
+       state->reg80 = val;
+
+setstd_exit:
+       if (err != 0)
+               v4l2_err(sd, "Error setting std, write failed\n");
+
+       return err;
+}
+
+static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
+{
+       struct adv7343_state *state = to_state(sd);
+       unsigned char val;
+       int err = 0;
+
+       if (output_type > ADV7343_SVIDEO_ID) {
+               v4l2_dbg(1, debug, sd,
+                       "Invalid output type or output type not supported:%d\n",
+                                                               output_type);
+               return -EINVAL;
+       }
+
+       /* Enable Appropriate DAC */
+       val = state->reg00 & 0x03;
+
+       if (output_type == ADV7343_COMPOSITE_ID)
+               val |= ADV7343_COMPOSITE_POWER_VALUE;
+       else if (output_type == ADV7343_COMPONENT_ID)
+               val |= ADV7343_COMPONENT_POWER_VALUE;
+       else
+               val |= ADV7343_SVIDEO_POWER_VALUE;
+
+       err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg00 = val;
+
+       /* Enable YUV output */
+       val = state->reg02 | YUV_OUTPUT_SELECT;
+       err = adv7343_write(sd, ADV7343_MODE_REG0, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg02 = val;
+
+       /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
+       val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
+       err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg82 = val;
+
+       /* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to
+        * zero */
+       val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI);
+       err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg35 = val;
+
+setoutput_exit:
+       if (err != 0)
+               v4l2_err(sd, "Error setting output, write failed\n");
+
+       return err;
+}
+
+static int adv7343_log_status(struct v4l2_subdev *sd)
+{
+       struct adv7343_state *state = to_state(sd);
+
+       v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
+       v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
+                       ((state->output == 1) ? "Component" : "S-Video"));
+       return 0;
+}
+
+static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN,
+                                               ADV7343_BRIGHTNESS_MAX, 1,
+                                               ADV7343_BRIGHTNESS_DEF);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN,
+                                               ADV7343_HUE_MAX, 1 ,
+                                               ADV7343_HUE_DEF);
+       case V4L2_CID_GAIN:
+               return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN,
+                                               ADV7343_GAIN_MAX, 1,
+                                               ADV7343_GAIN_DEF);
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct adv7343_state *state = to_state(sd);
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if (ctrl->value < ADV7343_BRIGHTNESS_MIN ||
+                                       ctrl->value > ADV7343_BRIGHTNESS_MAX) {
+                       v4l2_dbg(1, debug, sd,
+                                       "invalid brightness settings %d\n",
+                                                               ctrl->value);
+                       return -ERANGE;
+               }
+
+               state->bright = ctrl->value;
+               err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
+                                       state->bright);
+               break;
+
+       case V4L2_CID_HUE:
+               if (ctrl->value < ADV7343_HUE_MIN ||
+                                       ctrl->value > ADV7343_HUE_MAX) {
+                       v4l2_dbg(1, debug, sd, "invalid hue settings %d\n",
+                                                               ctrl->value);
+                       return -ERANGE;
+               }
+
+               state->hue = ctrl->value;
+               err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue);
+               break;
+
+       case V4L2_CID_GAIN:
+               if (ctrl->value < ADV7343_GAIN_MIN ||
+                                       ctrl->value > ADV7343_GAIN_MAX) {
+                       v4l2_dbg(1, debug, sd, "invalid gain settings %d\n",
+                                                               ctrl->value);
+                       return -ERANGE;
+               }
+
+               if ((ctrl->value > POSITIVE_GAIN_MAX) &&
+                       (ctrl->value < NEGATIVE_GAIN_MIN)) {
+                       v4l2_dbg(1, debug, sd,
+                               "gain settings not within the specified range\n");
+                       return -ERANGE;
+               }
+
+               state->gain = ctrl->value;
+               err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (err < 0)
+               v4l2_err(sd, "Failed to set the encoder controls\n");
+
+       return err;
+}
+
+static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct adv7343_state *state = to_state(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = state->bright;
+               break;
+
+       case V4L2_CID_HUE:
+               ctrl->value = state->hue;
+               break;
+
+       case V4L2_CID_GAIN:
+               ctrl->value = state->gain;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
+}
+
+static const struct v4l2_subdev_core_ops adv7343_core_ops = {
+       .log_status     = adv7343_log_status,
+       .g_chip_ident   = adv7343_g_chip_ident,
+       .g_ctrl         = adv7343_g_ctrl,
+       .s_ctrl         = adv7343_s_ctrl,
+       .queryctrl      = adv7343_queryctrl,
+};
+
+static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct adv7343_state *state = to_state(sd);
+       int err = 0;
+
+       if (state->std == std)
+               return 0;
+
+       err = adv7343_setstd(sd, std);
+       if (!err)
+               state->std = std;
+
+       return err;
+}
+
+static int adv7343_s_routing(struct v4l2_subdev *sd,
+               u32 input, u32 output, u32 config)
+{
+       struct adv7343_state *state = to_state(sd);
+       int err = 0;
+
+       if (state->output == output)
+               return 0;
+
+       err = adv7343_setoutput(sd, output);
+       if (!err)
+               state->output = output;
+
+       return err;
+}
+
+static const struct v4l2_subdev_video_ops adv7343_video_ops = {
+       .s_std_output   = adv7343_s_std_output,
+       .s_routing      = adv7343_s_routing,
+};
+
+static const struct v4l2_subdev_ops adv7343_ops = {
+       .core   = &adv7343_core_ops,
+       .video  = &adv7343_video_ops,
+};
+
+static int adv7343_initialize(struct v4l2_subdev *sd)
+{
+       struct adv7343_state *state = to_state(sd);
+       int err = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) {
+
+               err = adv7343_write(sd, adv7343_init_reg_val[i],
+                                       adv7343_init_reg_val[i+1]);
+               if (err) {
+                       v4l2_err(sd, "Error initializing\n");
+                       return err;
+               }
+       }
+
+       /* Configure for default video standard */
+       err = adv7343_setoutput(sd, state->output);
+       if (err < 0) {
+               v4l2_err(sd, "Error setting output during init\n");
+               return -EINVAL;
+       }
+
+       err = adv7343_setstd(sd, state->std);
+       if (err < 0) {
+               v4l2_err(sd, "Error setting std during init\n");
+               return -EINVAL;
+       }
+
+       return err;
+}
+
+static int adv7343_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct adv7343_state *state;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL);
+       if (state == NULL)
+               return -ENOMEM;
+
+       state->reg00    = 0x80;
+       state->reg01    = 0x00;
+       state->reg02    = 0x20;
+       state->reg35    = 0x00;
+       state->reg80    = ADV7343_SD_MODE_REG1_DEFAULT;
+       state->reg82    = ADV7343_SD_MODE_REG2_DEFAULT;
+
+       state->output = ADV7343_COMPOSITE_ID;
+       state->std = V4L2_STD_NTSC;
+
+       v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);
+       return adv7343_initialize(&state->sd);
+}
+
+static int adv7343_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
+
+       return 0;
+}
+
+static const struct i2c_device_id adv7343_id[] = {
+       {"adv7343", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7343_id);
+
+static struct i2c_driver adv7343_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "adv7343",
+       },
+       .probe          = adv7343_probe,
+       .remove         = adv7343_remove,
+       .id_table       = adv7343_id,
+};
+
+static __init int init_adv7343(void)
+{
+       return i2c_add_driver(&adv7343_driver);
+}
+
+static __exit void exit_adv7343(void)
+{
+       i2c_del_driver(&adv7343_driver);
+}
+
+module_init(init_adv7343);
+module_exit(exit_adv7343);
diff --git a/drivers/media/video/adv7343_regs.h b/drivers/media/video/adv7343_regs.h
new file mode 100644 (file)
index 0000000..3431045
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * ADV7343 encoder related structure and register definitions
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ADV7343_REG_H
+#define ADV7343_REGS_H
+
+struct adv7343_std_info {
+       u32 standard_val3;
+       u32 fsc_val;
+       v4l2_std_id stdid;
+};
+
+/* Register offset macros */
+#define ADV7343_POWER_MODE_REG         (0x00)
+#define ADV7343_MODE_SELECT_REG                (0x01)
+#define ADV7343_MODE_REG0              (0x02)
+
+#define ADV7343_DAC2_OUTPUT_LEVEL      (0x0b)
+
+#define ADV7343_SOFT_RESET             (0x17)
+
+#define ADV7343_HD_MODE_REG1           (0x30)
+#define ADV7343_HD_MODE_REG2           (0x31)
+#define ADV7343_HD_MODE_REG3           (0x32)
+#define ADV7343_HD_MODE_REG4           (0x33)
+#define ADV7343_HD_MODE_REG5           (0x34)
+#define ADV7343_HD_MODE_REG6           (0x35)
+
+#define ADV7343_HD_MODE_REG7           (0x39)
+
+#define ADV7343_SD_MODE_REG1           (0x80)
+#define ADV7343_SD_MODE_REG2           (0x82)
+#define ADV7343_SD_MODE_REG3           (0x83)
+#define ADV7343_SD_MODE_REG4           (0x84)
+#define ADV7343_SD_MODE_REG5           (0x86)
+#define ADV7343_SD_MODE_REG6           (0x87)
+#define ADV7343_SD_MODE_REG7           (0x88)
+#define ADV7343_SD_MODE_REG8           (0x89)
+
+#define ADV7343_FSC_REG0               (0x8C)
+#define ADV7343_FSC_REG1               (0x8D)
+#define ADV7343_FSC_REG2               (0x8E)
+#define ADV7343_FSC_REG3               (0x8F)
+
+#define ADV7343_SD_CGMS_WSS0           (0x99)
+
+#define ADV7343_SD_HUE_REG             (0xA0)
+#define ADV7343_SD_BRIGHTNESS_WSS      (0xA1)
+
+/* Default values for the registers */
+#define ADV7343_POWER_MODE_REG_DEFAULT         (0x10)
+#define ADV7343_HD_MODE_REG1_DEFAULT           (0x3C)  /* Changed Default
+                                                          720p EAVSAV code*/
+#define ADV7343_HD_MODE_REG2_DEFAULT           (0x01)  /* Changed Pixel data
+                                                          valid */
+#define ADV7343_HD_MODE_REG3_DEFAULT           (0x00)  /* Color delay 0 clks */
+#define ADV7343_HD_MODE_REG4_DEFAULT           (0xE8)  /* Changed */
+#define ADV7343_HD_MODE_REG5_DEFAULT           (0x08)
+#define ADV7343_HD_MODE_REG6_DEFAULT           (0x00)
+#define ADV7343_HD_MODE_REG7_DEFAULT           (0x00)
+#define ADV7343_SD_MODE_REG8_DEFAULT           (0x00)
+#define ADV7343_SOFT_RESET_DEFAULT             (0x02)
+#define ADV7343_COMPOSITE_POWER_VALUE          (0x80)
+#define ADV7343_COMPONENT_POWER_VALUE          (0x1C)
+#define ADV7343_SVIDEO_POWER_VALUE             (0x60)
+#define ADV7343_SD_HUE_REG_DEFAULT             (127)
+#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT      (0x03)
+
+#define ADV7343_SD_CGMS_WSS0_DEFAULT           (0x10)
+
+#define ADV7343_SD_MODE_REG1_DEFAULT           (0x00)
+#define ADV7343_SD_MODE_REG2_DEFAULT           (0xC9)
+#define ADV7343_SD_MODE_REG3_DEFAULT           (0x10)
+#define ADV7343_SD_MODE_REG4_DEFAULT           (0x01)
+#define ADV7343_SD_MODE_REG5_DEFAULT           (0x02)
+#define ADV7343_SD_MODE_REG6_DEFAULT           (0x0C)
+#define ADV7343_SD_MODE_REG7_DEFAULT           (0x04)
+#define ADV7343_SD_MODE_REG8_DEFAULT           (0x00)
+
+/* Bit masks for Mode Select Register */
+#define INPUT_MODE_MASK                        (0x70)
+#define SD_INPUT_MODE                  (0x00)
+#define HD_720P_INPUT_MODE             (0x10)
+#define HD_1080I_INPUT_MODE            (0x10)
+
+/* Bit masks for Mode Register 0 */
+#define TEST_PATTERN_BLACK_BAR_EN      (0x04)
+#define YUV_OUTPUT_SELECT              (0x20)
+#define RGB_OUTPUT_SELECT              (0xDF)
+
+/* Bit masks for DAC output levels */
+#define DAC_OUTPUT_LEVEL_MASK          (0xFF)
+#define POSITIVE_GAIN_MAX              (0x40)
+#define POSITIVE_GAIN_MIN              (0x00)
+#define NEGATIVE_GAIN_MAX              (0xFF)
+#define NEGATIVE_GAIN_MIN              (0xC0)
+
+/* Bit masks for soft reset register */
+#define SOFT_RESET                     (0x02)
+
+/* Bit masks for HD Mode Register 1 */
+#define OUTPUT_STD_MASK                (0x03)
+#define OUTPUT_STD_SHIFT       (0)
+#define OUTPUT_STD_EIA0_2      (0x00)
+#define OUTPUT_STD_EIA0_1      (0x01)
+#define OUTPUT_STD_FULL                (0x02)
+#define EMBEDDED_SYNC          (0x04)
+#define EXTERNAL_SYNC          (0xFB)
+#define STD_MODE_SHIFT         (3)
+#define STD_MODE_MASK          (0x1F)
+#define STD_MODE_720P          (0x05)
+#define STD_MODE_720P_25       (0x08)
+#define STD_MODE_720P_30       (0x07)
+#define STD_MODE_720P_50       (0x06)
+#define STD_MODE_1080I         (0x0D)
+#define STD_MODE_1080I_25fps   (0x0E)
+#define STD_MODE_1080P_24      (0x12)
+#define STD_MODE_1080P_25      (0x10)
+#define STD_MODE_1080P_30      (0x0F)
+#define STD_MODE_525P          (0x00)
+#define STD_MODE_625P          (0x03)
+
+/* Bit masks for SD Mode Register 1 */
+#define SD_STD_MASK            (0x03)
+#define SD_STD_NTSC            (0x00)
+#define SD_STD_PAL_BDGHI       (0x01)
+#define SD_STD_PAL_M           (0x02)
+#define SD_STD_PAL_N           (0x03)
+#define SD_LUMA_FLTR_MASK      (0x7)
+#define SD_LUMA_FLTR_SHIFT     (0x2)
+#define SD_CHROMA_FLTR_MASK    (0x7)
+#define SD_CHROMA_FLTR_SHIFT   (0x5)
+
+/* Bit masks for SD Mode Register 2 */
+#define SD_PBPR_SSAF_EN                (0x01)
+#define SD_PBPR_SSAF_DI                (0xFE)
+#define SD_DAC_1_DI            (0xFD)
+#define SD_DAC_2_DI            (0xFB)
+#define SD_PEDESTAL_EN         (0x08)
+#define SD_PEDESTAL_DI         (0xF7)
+#define SD_SQUARE_PIXEL_EN     (0x10)
+#define SD_SQUARE_PIXEL_DI     (0xEF)
+#define SD_PIXEL_DATA_VALID    (0x40)
+#define SD_ACTIVE_EDGE_EN      (0x80)
+#define SD_ACTIVE_EDGE_DI      (0x7F)
+
+/* Bit masks for HD Mode Register 6 */
+#define HD_RGB_INPUT_EN                (0x02)
+#define HD_RGB_INPUT_DI                (0xFD)
+#define HD_PBPR_SYNC_EN                (0x04)
+#define HD_PBPR_SYNC_DI                (0xFB)
+#define HD_DAC_SWAP_EN         (0x08)
+#define HD_DAC_SWAP_DI         (0xF7)
+#define HD_GAMMA_CURVE_A       (0xEF)
+#define HD_GAMMA_CURVE_B       (0x10)
+#define HD_GAMMA_EN            (0x20)
+#define HD_GAMMA_DI            (0xDF)
+#define HD_ADPT_FLTR_MODEB     (0x40)
+#define HD_ADPT_FLTR_MODEA     (0xBF)
+#define HD_ADPT_FLTR_EN                (0x80)
+#define HD_ADPT_FLTR_DI                (0x7F)
+
+#define ADV7343_BRIGHTNESS_MAX (127)
+#define ADV7343_BRIGHTNESS_MIN (0)
+#define ADV7343_BRIGHTNESS_DEF (3)
+#define ADV7343_HUE_MAX                (255)
+#define ADV7343_HUE_MIN                (0)
+#define ADV7343_HUE_DEF                (127)
+#define ADV7343_GAIN_MAX       (255)
+#define ADV7343_GAIN_MIN       (0)
+#define ADV7343_GAIN_DEF       (0)
+
+#endif
index 053bbe8c8e3aaf89bd8850c5196400fdeb34e129..830c4a933f635ffc8256bd3deff50409380aa1bb 100644 (file)
@@ -136,9 +136,9 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
                        /* Tuner Reset Command from xc5000 */
                        /* Drive the tuner into reset and out */
                        au0828_clear(dev, REG_001, 2);
-                       mdelay(200);
+                       mdelay(10);
                        au0828_set(dev, REG_001, 2);
-                       mdelay(50);
+                       mdelay(10);
                        return 0;
                } else {
                        printk(KERN_ERR
index a1e4c0d769a6d014329165764647fc2c4c02568b..3544a2f12f13a1497f54ca30609a26e8e9ba8a49 100644 (file)
@@ -36,6 +36,11 @@ int au0828_debug;
 module_param_named(debug, au0828_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+                "override min bandwidth requirement of 480M bps");
+
 #define _AU0828_BULKPIPE 0x03
 #define _BULKPIPESIZE 0xffff
 
@@ -181,6 +186,18 @@ static int au0828_usb_probe(struct usb_interface *interface,
                le16_to_cpu(usbdev->descriptor.idProduct),
                ifnum);
 
+       /*
+        * Make sure we have 480 Mbps of bandwidth, otherwise things like
+        * video stream wouldn't likely work, since 12 Mbps is generally
+        * not enough even for most Digital TV streams.
+        */
+       if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+               printk(KERN_ERR "au0828: Device initialization failed.\n");
+               printk(KERN_ERR "au0828: Device must be connected to a "
+                      "high-speed USB 2.0 port.\n");
+               return -ENODEV;
+       }
+
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
index 27bedc6c779114da92758f7efb494fa3ca6582f0..51527d7b55a757124e546fa4842efbac67c48688 100644 (file)
@@ -829,6 +829,9 @@ static int au0828_v4l2_close(struct file *filp)
 
                au0828_uninit_isoc(dev);
 
+               /* Save some power by putting tuner to sleep */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
+
                /* When close the device, set the usb intf0 into alt0 to free
                   USB bandwidth */
                ret = usb_set_interface(dev->usbdev, 0, 0);
@@ -910,11 +913,6 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
 
        rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 
-       dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n",
-               (unsigned long)vma->vm_start,
-               (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
-               rc);
-
        return rc;
 }
 
index 23b7499b31852d5aa7f0b3f52c5f5c2f37b481f6..5eb1464af6703f3825599e05bc4683a2e09dc250 100644 (file)
@@ -3152,6 +3152,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
        struct bttv_fh *fh = file->private_data;
        struct bttv_buffer *buf;
        enum v4l2_field field;
+       unsigned int rc = POLLERR;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
                if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
@@ -3160,9 +3161,10 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
        }
 
        if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
+               mutex_lock(&fh->cap.vb_lock);
                /* streaming capture */
                if (list_empty(&fh->cap.stream))
-                       return POLLERR;
+                       goto err;
                buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
        } else {
                /* read() capture */
@@ -3191,11 +3193,12 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
        poll_wait(file, &buf->vb.done, wait);
        if (buf->vb.state == VIDEOBUF_DONE ||
            buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
+               rc =  POLLIN|POLLRDNORM;
+       else
+               rc = 0;
 err:
        mutex_unlock(&fh->cap.vb_lock);
-       return POLLERR;
+       return rc;
 }
 
 static int bttv_open(struct file *file)
@@ -4166,7 +4169,6 @@ static struct video_device *vdev_init(struct bttv *btv,
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       vfd->minor   = -1;
        vfd->v4l2_dev = &btv->c.v4l2_dev;
        vfd->release = video_device_release;
        vfd->debug   = bttv_debug;
@@ -4629,7 +4631,7 @@ static int __init bttv_init_module(void)
 #endif
        if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
                gbuffers = 2;
-       if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
+       if (gbufsize > BTTV_MAX_FBUF)
                gbufsize = BTTV_MAX_FBUF;
        gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
        if (bttv_verbose)
index a99d92fac3dc4e7731cfa9b2349886ac926b6d6c..ebd1ee9dc871d222f6f918b8670aa407037e9777 100644 (file)
@@ -389,6 +389,27 @@ int __devinit init_bttv_i2c(struct bttv *btv)
        }
        if (0 == btv->i2c_rc && i2c_scan)
                do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
+
+       /* Instantiate the IR receiver device, if present */
+       if (0 == btv->i2c_rc) {
+               struct i2c_board_info info;
+               /* The external IR receiver is at i2c address 0x34 (0x35 for
+                  reads).  Future Hauppauge cards will have an internal
+                  receiver at 0x30 (0x31 for reads).  In theory, both can be
+                  fitted, and Hauppauge suggest an external overrides an
+                  internal.
+
+                  That's why we probe 0x1a (~0x34) first. CB
+               */
+               const unsigned short addr_list[] = {
+                       0x1a, 0x18, 0x4b, 0x64, 0x30,
+                       I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
+       }
        return btv->i2c_rc;
 }
 
index d4099f5312ac4ab8ac2ad00b1eb9ae405e847c2d..0b4a8f309cfab14c65727e378cc6d352b3bea881 100644 (file)
@@ -1064,7 +1064,7 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam)
 
        switch(m->id) {
        case CPIA2_CID_FLICKER_MODE:
-               if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS)
+               if (m->index >= NUM_FLICKER_CONTROLS)
                        return -EINVAL;
 
                strcpy(m->name, flicker_controls[m->index].name);
@@ -1082,14 +1082,14 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam)
                                        maximum = i;
                        }
                }
-               if(m->index < 0 || m->index > maximum)
+               if (m->index > maximum)
                        return -EINVAL;
 
                strcpy(m->name, framerate_controls[m->index].name);
                break;
            }
        case CPIA2_CID_LIGHTS:
-               if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS)
+               if (m->index >= NUM_LIGHTS_CONTROLS)
                        return -EINVAL;
 
                strcpy(m->name, lights_controls[m->index].name);
index 7a8ad5963de8c774b7ac5368c8f2729d44e6e00f..35268923911c94b88bf527bc0734941cd3617b95 100644 (file)
 #include "cx18-cards.h"
 #include "cx18-audio.h"
 
-#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AUDIO_ENABLE    0xc72014
+#define CX18_AI1_MUX_MASK    0x30
+#define CX18_AI1_MUX_I2S1    0x00
+#define CX18_AI1_MUX_I2S2    0x10
+#define CX18_AI1_MUX_843_I2S 0x20
 
 /* Selects the audio input and output according to the current
    settings. */
 int cx18_audio_set_io(struct cx18 *cx)
 {
        const struct cx18_card_audio_input *in;
-       u32 val;
+       u32 u, v;
        int err;
 
        /* Determine which input to use */
@@ -52,9 +56,37 @@ int cx18_audio_set_io(struct cx18 *cx)
                return err;
 
        /* FIXME - this internal mux should be abstracted to a subdev */
-       val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
-       val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
-                                       (in->audio_input << 4);
-       cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30);
+       u = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+       v = u & ~CX18_AI1_MUX_MASK;
+       switch (in->audio_input) {
+       case CX18_AV_AUDIO_SERIAL1:
+               v |= CX18_AI1_MUX_I2S1;
+               break;
+       case CX18_AV_AUDIO_SERIAL2:
+               v |= CX18_AI1_MUX_I2S2;
+               break;
+       default:
+               v |= CX18_AI1_MUX_843_I2S;
+               break;
+       }
+       if (v == u) {
+               /* force a toggle of some AI1 MUX control bits */
+               u &= ~CX18_AI1_MUX_MASK;
+               switch (in->audio_input) {
+               case CX18_AV_AUDIO_SERIAL1:
+                       u |= CX18_AI1_MUX_843_I2S;
+                       break;
+               case CX18_AV_AUDIO_SERIAL2:
+                       u |= CX18_AI1_MUX_843_I2S;
+                       break;
+               default:
+                       u |= CX18_AI1_MUX_I2S1;
+                       break;
+               }
+               cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE,
+                                     u, CX18_AI1_MUX_MASK);
+       }
+       cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+                             v, CX18_AI1_MUX_MASK);
        return 0;
 }
index cf2bd888a429a8e00d45304bd48644fa7efdbdc2..536dedb23ba36cb3080a53c0e958c6049d20300c 100644 (file)
@@ -99,9 +99,39 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
                             or_value);
 }
 
-static void cx18_av_initialize(struct cx18 *cx)
+static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
 {
-       struct cx18_av_state *state = &cx->av_state;
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+       /*
+        * The crystal freq used in calculations in this driver will be
+        * 28.636360 MHz.
+        * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+        */
+
+       /*
+        * VDCLK  Integer = 0x0f, Post Divider = 0x04
+        * AIMCLK Integer = 0x0e, Post Divider = 0x16
+        */
+       cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+
+       /* VDCLK Fraction = 0x2be2fe */
+       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+       cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+
+       /* AIMCLK Fraction = 0x05227ad */
+       /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
+       cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+
+       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+       cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+       return 0;
+}
+
+static void cx18_av_initialize(struct v4l2_subdev *sd)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
        u32 v;
 
        cx18_av_loadfw(cx);
@@ -150,6 +180,26 @@ static void cx18_av_initialize(struct cx18 *cx)
        cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
        cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
 
+       /*
+        * Disable Video Auto-config of the Analog Front End and Video PLL.
+        *
+        * Since we only use BT.656 pixel mode, which works for both 525 and 625
+        * line systems, it's just easier for us to set registers
+        * 0x102 (CXADEC_CHIP_CTRL), 0x104-0x106 (CXADEC_AFE_CTRL),
+        * 0x108-0x109 (CXADEC_PLL_CTRL1), and 0x10c-0x10f (CXADEC_VID_PLL_FRAC)
+        * ourselves, than to run around cleaning up after the auto-config.
+        *
+        * (Note: my CX23418 chip doesn't seem to let the ACFG_DIS bit
+        * get set to 1, but OTOH, it doesn't seem to do AFE and VID PLL
+        * autoconfig either.)
+        *
+        * As a default, also turn off Dual mode for ADC2 and set ADC2 to CH3.
+        */
+       cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000);
+
+       /* Setup the Video and and Aux/Audio PLLs */
+       cx18_av_init(sd, 0);
+
        /* set video to auto-detect */
        /* Clear bits 11-12 to enable slow locking mode.  Set autodetect mode */
        /* set the comb notch = 1 */
@@ -176,12 +226,23 @@ static void cx18_av_initialize(struct cx18 *cx)
        /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
        /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
 
-       v = cx18_av_read4(cx, CXADEC_AFE_CTRL);
-       v &= 0xFFFBFFFF;            /* turn OFF bit 18 for droop_comp_ch1 */
-       v &= 0xFFFF7FFF;            /* turn OFF bit 9 for clamp_sel_ch1 */
-       v &= 0xFFFFFFFE;            /* turn OFF bit 0 for 12db_ch1 */
-       /* v |= 0x00000001;*/            /* turn ON bit 0 for 12db_ch1 */
-       cx18_av_write4(cx, CXADEC_AFE_CTRL, v);
+       /*
+        * Analog Front End (AFE)
+        * Default to luma on ch1/ADC1, chroma on ch2/ADC2, SIF on ch3/ADC2
+        *  bypass_ch[1-3]     use filter
+        *  droop_comp_ch[1-3] disable
+        *  clamp_en_ch[1-3]   disable
+        *  aud_in_sel         ADC2
+        *  luma_in_sel        ADC1
+        *  chroma_in_sel      ADC2
+        *  clamp_sel_ch[2-3]  midcode
+        *  clamp_sel_ch1      video decoder
+        *  vga_sel_ch3        audio decoder
+        *  vga_sel_ch[1-2]    video decoder
+        *  half_bw_ch[1-3]    disable
+        *  +12db_ch[1-3]      disable
+        */
+       cx18_av_and_or4(cx, CXADEC_AFE_CTRL, 0xFF000000, 0x00005D00);
 
 /*     if(dwEnable && dw3DCombAvailable) { */
 /*             CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
@@ -195,50 +256,18 @@ static void cx18_av_initialize(struct cx18 *cx)
 
 static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
 {
-       struct cx18 *cx = v4l2_get_subdevdata(sd);
-
-       cx18_av_initialize(cx);
-       return 0;
-}
-
-static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
-{
-       struct cx18 *cx = v4l2_get_subdevdata(sd);
-
-       /*
-        * The crystal freq used in calculations in this driver will be
-        * 28.636360 MHz.
-        * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
-        */
-
-       /*
-        * VDCLK  Integer = 0x0f, Post Divider = 0x04
-        * AIMCLK Integer = 0x0e, Post Divider = 0x16
-        */
-       cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
-
-       /* VDCLK Fraction = 0x2be2fe */
-       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
-       cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
-
-       /* AIMCLK Fraction = 0x05227ad */
-       /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
-       cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
-
-       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
-       cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+       cx18_av_initialize(sd);
        return 0;
 }
 
 static int cx18_av_load_fw(struct v4l2_subdev *sd)
 {
        struct cx18_av_state *state = to_cx18_av_state(sd);
-       struct cx18 *cx = v4l2_get_subdevdata(sd);
 
        if (!state->is_initialized) {
                /* initialize on first use */
                state->is_initialized = 1;
-               cx18_av_initialize(cx);
+               cx18_av_initialize(sd);
        }
        return 0;
 }
@@ -248,8 +277,15 @@ void cx18_av_std_setup(struct cx18 *cx)
        struct cx18_av_state *state = &cx->av_state;
        struct v4l2_subdev *sd = &state->sd;
        v4l2_std_id std = state->std;
+
+       /*
+        * Video ADC crystal clock to pixel clock SRC decimation ratio
+        * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b
+        */
+       const int src_decimation = 0x21f;
+
        int hblank, hactive, burst, vblank, vactive, sc;
-       int vblank656, src_decimation;
+       int vblank656;
        int luma_lpf, uv_lpf, comb;
        u32 pll_int, pll_frac, pll_post;
 
@@ -259,40 +295,96 @@ void cx18_av_std_setup(struct cx18 *cx)
        else
                cx18_av_write(cx, 0x49f, 0x14);
 
+       /*
+        * Note: At the end of a field, there are 3 sets of half line duration
+        * (double horizontal rate) pulses:
+        *
+        * 5 (625) or 6 (525) half-lines to blank for the vertical retrace
+        * 5 (625) or 6 (525) vertical sync pulses of half line duration
+        * 5 (625) or 6 (525) half-lines of equalization pulses
+        */
        if (std & V4L2_STD_625_50) {
-               /* FIXME - revisit these for Sliced VBI */
+               /*
+                * The following relationships of half line counts should hold:
+                * 625 = vblank656 + vactive
+                * 10 = vblank656 - vblank = vsync pulses + equalization pulses
+                *
+                * vblank656: half lines after line 625/mid-313 of blanked video
+                * vblank:    half lines, after line 5/317, of blanked video
+                * vactive:   half lines of active video +
+                *              5 half lines after the end of active video
+                *
+                * As far as I can tell:
+                * vblank656 starts counting from the falling edge of the first
+                *      vsync pulse (start of line 1 or mid-313)
+                * vblank starts counting from the after the 5 vsync pulses and
+                *      5 or 4 equalization pulses (start of line 6 or 318)
+                *
+                * For 625 line systems the driver will extract VBI information
+                * from lines 6-23 and lines 318-335 (but the slicer can only
+                * handle 17 lines, not the 18 in the vblank region).
+                * In addition, we need vblank656 and vblank to be one whole
+                * line longer, to cover line 24 and 336, so the SAV/EAV RP
+                * codes get generated such that the encoder can actually
+                * extract line 23 & 335 (WSS).  We'll lose 1 line in each field
+                * at the top of the screen.
+                *
+                * It appears the 5 half lines that happen after active
+                * video must be included in vactive (579 instead of 574),
+                * otherwise the colors get badly displayed in various regions
+                * of the screen.  I guess the chroma comb filter gets confused
+                * without them (at least when a PVR-350 is the PAL source).
+                */
+               vblank656 = 48; /* lines  1 -  24  &  313 - 336 */
+               vblank = 38;    /* lines  6 -  24  &  318 - 336 */
+               vactive = 579;  /* lines 24 - 313  &  337 - 626 */
+
+               /*
+                * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is
+                * is 864 pixels = 720 active + 144 blanking.  ITU-R BT.601
+                * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after
+                * the end of active video to start a horizontal line, so that
+                * leaves 132 pixels of hblank to ignore.
+                */
                hblank = 132;
                hactive = 720;
-               burst = 93;
-               vblank = 36;
-               vactive = 580;
-               vblank656 = 40;
-               src_decimation = 0x21f;
 
+               /*
+                * Burst gate delay (for 625 line systems)
+                * Hsync leading edge to color burst rise = 5.6 us
+                * Color burst width = 2.25 us
+                * Gate width = 4 pixel clocks
+                * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks
+                */
+               burst = 93;
                luma_lpf = 2;
                if (std & V4L2_STD_PAL) {
                        uv_lpf = 1;
                        comb = 0x20;
-                       sc = 688739;
+                       /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+                       sc = 688700;
                } else if (std == V4L2_STD_PAL_Nc) {
                        uv_lpf = 1;
                        comb = 0x20;
-                       sc = 556453;
+                       /* sc = 3582056.25 * src_decimation/28636360 * 2^13 */
+                       sc = 556422;
                } else { /* SECAM */
                        uv_lpf = 0;
                        comb = 0;
-                       sc = 672351;
+                       /* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */
+                       /* sc = 4328130 * src_decimation/28636360 * 2^13 */
+                       sc = 672314;
                }
        } else {
                /*
                 * The following relationships of half line counts should hold:
-                * 525 = vsync + vactive + vblank656
-                * 12 = vblank656 - vblank
+                * 525 = prevsync + vblank656 + vactive
+                * 12 = vblank656 - vblank = vsync pulses + equalization pulses
                 *
-                * vsync:     always 6 half-lines of vsync pulses
-                * vactive:   half lines of active video
+                * prevsync:  6 half-lines before the vsync pulses
                 * vblank656: half lines, after line 3/mid-266, of blanked video
                 * vblank:    half lines, after line 9/272, of blanked video
+                * vactive:   half lines of active video
                 *
                 * As far as I can tell:
                 * vblank656 starts counting from the falling edge of the first
@@ -319,20 +411,30 @@ void cx18_av_std_setup(struct cx18 *cx)
                luma_lpf = 1;
                uv_lpf = 1;
 
-               src_decimation = 0x21f;
+               /*
+                * Burst gate delay (for 525 line systems)
+                * Hsync leading edge to color burst rise = 5.3 us
+                * Color burst width = 2.5 us
+                * Gate width = 4 pixel clocks
+                * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks
+                */
                if (std == V4L2_STD_PAL_60) {
-                       burst = 0x5b;
+                       burst = 90;
                        luma_lpf = 2;
                        comb = 0x20;
-                       sc = 688739;
+                       /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+                       sc = 688700;
                } else if (std == V4L2_STD_PAL_M) {
-                       burst = 0x61;
+                       /* The 97 needs to be verified against PAL-M timings */
+                       burst = 97;
                        comb = 0x20;
-                       sc = 555452;
+                       /* sc = 3575611.49 * src_decimation/28636360 * 2^13 */
+                       sc = 555421;
                } else {
-                       burst = 0x5b;
+                       burst = 90;
                        comb = 0x66;
-                       sc = 556063;
+                       /* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */
+                       sc = 556032;
                }
        }
 
@@ -344,23 +446,26 @@ void cx18_av_std_setup(struct cx18 *cx)
                            pll_int, pll_frac, pll_post);
 
        if (pll_post) {
-               int fin, fsc, pll;
+               int fsc, pll;
+               u64 tmp;
 
                pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
                pll /= pll_post;
-               CX18_DEBUG_INFO_DEV(sd, "PLL = %d.%06d MHz\n",
+               CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n",
                                    pll / 1000000, pll % 1000000);
-               CX18_DEBUG_INFO_DEV(sd, "PLL/8 = %d.%06d MHz\n",
+               CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n",
                                    pll / 8000000, (pll / 8) % 1000000);
 
-               fin = ((u64)src_decimation * pll) >> 12;
-               CX18_DEBUG_INFO_DEV(sd, "ADC Sampling freq = %d.%06d MHz\n",
-                                   fin / 1000000, fin % 1000000);
+               CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio "
+                                   "= %d.%03d\n", src_decimation / 256,
+                                   ((src_decimation % 256) * 1000) / 256);
 
-               fsc = (((u64)sc) * pll) >> 24L;
+               tmp = 28636360 * (u64) sc;
+               do_div(tmp, src_decimation);
+               fsc = tmp >> 13;
                CX18_DEBUG_INFO_DEV(sd,
-                                   "Chroma sub-carrier freq = %d.%06d MHz\n",
-                                   fsc / 1000000, fsc % 1000000);
+                                   "Chroma sub-carrier initial freq = %d.%06d "
+                                   "MHz\n", fsc / 1000000, fsc % 1000000);
 
                CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, "
                                    "vactive %i, vblank656 %i, src_dec %i, "
@@ -470,16 +575,23 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
 {
        struct cx18_av_state *state = &cx->av_state;
        struct v4l2_subdev *sd = &state->sd;
-       u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
-                          vid_input <= CX18_AV_COMPOSITE8);
-       u8 reg;
-       u8 v;
+
+       enum analog_signal_type {
+               NONE, CVBS, Y, C, SIF, Pb, Pr
+       } ch[3] = {NONE, NONE, NONE};
+
+       u8 afe_mux_cfg;
+       u8 adc2_cfg;
+       u32 afe_cfg;
+       int i;
 
        CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n",
                            vid_input, aud_input);
 
-       if (is_composite) {
-               reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+       if (vid_input >= CX18_AV_COMPOSITE1 &&
+           vid_input <= CX18_AV_COMPOSITE8) {
+               afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+               ch[0] = CVBS;
        } else {
                int luma = vid_input & 0xf0;
                int chroma = vid_input & 0xf00;
@@ -493,26 +605,45 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
                                     vid_input);
                        return -EINVAL;
                }
-               reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+               afe_mux_cfg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+               ch[0] = Y;
                if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
-                       reg &= 0x3f;
-                       reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+                       afe_mux_cfg &= 0x3f;
+                       afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+                       ch[2] = C;
                } else {
-                       reg &= 0xcf;
-                       reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+                       afe_mux_cfg &= 0xcf;
+                       afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+                       ch[1] = C;
                }
        }
+       /* TODO: LeadTek WinFast DVR3100 H & WinFast PVR2100 can do Y/Pb/Pr */
 
        switch (aud_input) {
        case CX18_AV_AUDIO_SERIAL1:
        case CX18_AV_AUDIO_SERIAL2:
                /* do nothing, use serial audio input */
                break;
-       case CX18_AV_AUDIO4: reg &= ~0x30; break;
-       case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
-       case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
-       case CX18_AV_AUDIO7: reg &= ~0xc0; break;
-       case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+       case CX18_AV_AUDIO4:
+               afe_mux_cfg &= ~0x30;
+               ch[1] = SIF;
+               break;
+       case CX18_AV_AUDIO5:
+               afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x10;
+               ch[1] = SIF;
+               break;
+       case CX18_AV_AUDIO6:
+               afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x20;
+               ch[1] = SIF;
+               break;
+       case CX18_AV_AUDIO7:
+               afe_mux_cfg &= ~0xc0;
+               ch[2] = SIF;
+               break;
+       case CX18_AV_AUDIO8:
+               afe_mux_cfg = (afe_mux_cfg & ~0xc0) | 0x40;
+               ch[2] = SIF;
+               break;
 
        default:
                CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n",
@@ -520,24 +651,65 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
                return -EINVAL;
        }
 
-       cx18_av_write_expect(cx, 0x103, reg, reg, 0xf7);
+       /* Set up analog front end multiplexers */
+       cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7);
        /* Set INPUT_MODE to Composite (0) or S-Video (1) */
-       cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
+       cx18_av_and_or(cx, 0x401, ~0x6, ch[0] == CVBS ? 0 : 0x02);
 
        /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
-       v = cx18_av_read(cx, 0x102);
-       if (reg & 0x80)
-               v &= ~0x2;
+       adc2_cfg = cx18_av_read(cx, 0x102);
+       if (ch[2] == NONE)
+               adc2_cfg &= ~0x2; /* No sig on CH3, set ADC2 to CH2 for input */
        else
-               v |= 0x2;
+               adc2_cfg |= 0x2;  /* Signal on CH3, set ADC2 to CH3 for input */
+
        /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
-       if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
-               v |= 0x4;
+       if (ch[1] != NONE && ch[2] != NONE)
+               adc2_cfg |= 0x4; /* Set dual mode */
        else
-               v &= ~0x4;
-       cx18_av_write_expect(cx, 0x102, v, v, 0x17);
+               adc2_cfg &= ~0x4; /* Clear dual mode */
+       cx18_av_write_expect(cx, 0x102, adc2_cfg, adc2_cfg, 0x17);
+
+       /* Configure the analog front end */
+       afe_cfg = cx18_av_read4(cx, CXADEC_AFE_CTRL);
+       afe_cfg &= 0xff000000;
+       afe_cfg |= 0x00005000; /* CHROMA_IN, AUD_IN: ADC2; LUMA_IN: ADC1 */
+       if (ch[1] != NONE && ch[2] != NONE)
+               afe_cfg |= 0x00000030; /* half_bw_ch[2-3] since in dual mode */
+
+       for (i = 0; i < 3; i++) {
+               switch (ch[i]) {
+               default:
+               case NONE:
+                       /* CLAMP_SEL = Fixed to midcode clamp level */
+                       afe_cfg |= (0x00000200 << i);
+                       break;
+               case CVBS:
+               case Y:
+                       if (i > 0)
+                               afe_cfg |= 0x00002000; /* LUMA_IN_SEL: ADC2 */
+                       break;
+               case C:
+               case Pb:
+               case Pr:
+                       /* CLAMP_SEL = Fixed to midcode clamp level */
+                       afe_cfg |= (0x00000200 << i);
+                       if (i == 0 && ch[i] == C)
+                               afe_cfg &= ~0x00001000; /* CHROMA_IN_SEL ADC1 */
+                       break;
+               case SIF:
+                       /*
+                        * VGA_GAIN_SEL = Audio Decoder
+                        * CLAMP_SEL = Fixed to midcode clamp level
+                        */
+                       afe_cfg |= (0x00000240 << i);
+                       if (i == 0)
+                               afe_cfg &= ~0x00004000; /* AUD_IN_SEL ADC1 */
+                       break;
+               }
+       }
 
-       /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
+       cx18_av_write4(cx, CXADEC_AFE_CTRL, afe_cfg);
 
        state->vid_input = vid_input;
        state->aud_input = aud_input;
@@ -858,9 +1030,9 @@ static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
                 * cx18_av_std_setup(), above standard values:
                 *
                 * 480 + 1 for 60 Hz systems
-                * 576 + 4 for 50 Hz systems
+                * 576 + 3 for 50 Hz systems
                 */
-               Vlines = pix->height + (is_50Hz ? 4 : 1);
+               Vlines = pix->height + (is_50Hz ? 3 : 1);
 
                /*
                 * Invalid height and width scaling requests are:
index 49a55cc8d839af13bbbe3dca43c06dd70a443220..b9e8cc5d264a4ec12a45ab9bd0fd29bb6b386380 100644 (file)
 #include "cx18-io.h"
 #include <linux/firmware.h>
 
-#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AUDIO_ENABLE    0xc72014
+#define CX18_AI1_MUX_MASK    0x30
+#define CX18_AI1_MUX_I2S1    0x00
+#define CX18_AI1_MUX_I2S2    0x10
+#define CX18_AI1_MUX_843_I2S 0x20
+#define CX18_AI1_MUX_INVALID 0x30
+
 #define FWFILE "v4l-cx23418-dig.fw"
 
+static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw)
+{
+       struct v4l2_subdev *sd = &cx->av_state.sd;
+       int ret = 0;
+       const u8 *data;
+       u32 size;
+       int addr;
+       u32 expected, dl_control;
+
+       /* Ensure we put the 8051 in reset and enable firmware upload mode */
+       dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+       do {
+               dl_control &= 0x00ffffff;
+               dl_control |= 0x0f000000;
+               cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control);
+               dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+       } while ((dl_control & 0xff000000) != 0x0f000000);
+
+       /* Read and auto increment until at address 0x0000 */
+       while (dl_control & 0x3fff)
+               dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+
+       data = fw->data;
+       size = fw->size;
+       for (addr = 0; addr < size; addr++) {
+               dl_control &= 0xffff3fff; /* ignore top 2 bits of address */
+               expected = 0x0f000000 | ((u32)data[addr] << 16) | addr;
+               if (expected != dl_control) {
+                       CX18_ERR_DEV(sd, "verification of %s firmware load "
+                                    "failed: expected %#010x got %#010x\n",
+                                    FWFILE, expected, dl_control);
+                       ret = -EIO;
+                       break;
+               }
+               dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+       }
+       if (ret == 0)
+               CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n",
+                             FWFILE, size);
+       return ret;
+}
+
 int cx18_av_loadfw(struct cx18 *cx)
 {
        struct v4l2_subdev *sd = &cx->av_state.sd;
        const struct firmware *fw = NULL;
        u32 size;
-       u32 v;
+       u32 u, v;
        const u8 *ptr;
        int i;
        int retries1 = 0;
@@ -95,6 +143,12 @@ int cx18_av_loadfw(struct cx18 *cx)
        }
 
        cx18_av_write4_expect(cx, CXADEC_DL_CTL,
+                               0x03000000 | fw->size, 0x03000000, 0x13000000);
+
+       CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
+
+       if (cx18_av_verifyfw(cx, fw) == 0)
+               cx18_av_write4_expect(cx, CXADEC_DL_CTL,
                                0x13000000 | fw->size, 0x13000000, 0x13000000);
 
        /* Output to the 416 */
@@ -135,6 +189,28 @@ int cx18_av_loadfw(struct cx18 *cx)
                cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
                                      0, 0x400);
 
+       /* Toggle the AI1 MUX */
+       v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+       u = v & CX18_AI1_MUX_MASK;
+       v &= ~CX18_AI1_MUX_MASK;
+       if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) {
+               /* Switch to I2S1 */
+               v |= CX18_AI1_MUX_I2S1;
+               cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+                                     v, CX18_AI1_MUX_MASK);
+               /* Switch back to the A/V decoder core I2S output */
+               v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S;
+       } else {
+               /* Switch to the A/V decoder core I2S output */
+               v |= CX18_AI1_MUX_843_I2S;
+               cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+                                     v, CX18_AI1_MUX_MASK);
+               /* Switch back to I2S1 or I2S2 */
+               v = (v & ~CX18_AI1_MUX_MASK) | u;
+       }
+       cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+                             v, CX18_AI1_MUX_MASK);
+
        /* Enable WW auto audio standard detection */
        v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
        v |= 0xFF;   /* Auto by default */
@@ -143,7 +219,5 @@ int cx18_av_loadfw(struct cx18 *cx)
        cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
 
        release_firmware(fw);
-
-       CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
        return 0;
 }
index 23b31670bf1dbc9143028ac2b68b78a1fb6844a1..a51732bcca4b61343c09f4397c17f75f64243c97 100644 (file)
@@ -255,8 +255,8 @@ int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt)
        }
 
        cx18_av_write(cx, 0x43c, 0x16);
-       /* FIXME - should match vblank set in cx18_av_std_setup() */
-       cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
+       /* Should match vblank set in cx18_av_std_setup() */
+       cx18_av_write(cx, 0x474, is_pal ? 38 : 26);
        return 0;
 }
 
index 9bc221837847675b1643c8b38459acedb1303483..c92a25036f0e291768a131ceff4b349b59dd34cd 100644 (file)
@@ -340,13 +340,12 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
 
 static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
        { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100   */
-       { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
        { 0, 0, 0 }
 };
 
 static const struct cx18_card cx18_card_leadtek_pvr2100 = {
        .type = CX18_CARD_LEADTEK_PVR2100,
-       .name = "Leadtek WinFast PVR2100/DVR3100 H",
+       .name = "Leadtek WinFast PVR2100",
        .comment = "Experimenters and photos needed for device to work well.\n"
                  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
@@ -365,15 +364,12 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
                { CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
        },
        .tuners = {
-               /* XC3028 tuner */
+               /* XC2028 tuner */
                { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
        },
        .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
        .ddr = {
-               /*
-                * Pointer to proper DDR config values provided by
-                * Terry Wu <terrywu at leadtek.com.tw>
-                */
+               /* Pointer to proper DDR config values provided by Terry Wu */
                .chip_config = 0x303,
                .refresh = 0x3bb,
                .timing1 = 0x24220e83,
@@ -392,6 +388,58 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
 
 /* ------------------------------------------------------------------------- */
 
+/* Leadtek WinFast DVR3100 H */
+
+static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = {
+       { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
+       { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_leadtek_dvr3100h = {
+       .type = CX18_CARD_LEADTEK_DVR3100H,
+       .name = "Leadtek WinFast DVR3100 H",
+       .comment = "Simultaneous DVB-T and Analog capture supported,\n"
+                 "\texcept when capturing Analog from the antenna input.\n",
+       .v4l2_capabilities = CX18_CAP_ENCODER,
+       .hw_audio_ctrl = CX18_HW_418_AV,
+       .hw_muxer = CX18_HW_GPIO_MUX,
+       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
+                 CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+       .video_inputs = {
+               { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+               { CX18_CARD_INPUT_SVIDEO1,    1,
+                       CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+               { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
+       },
+       .audio_inputs = {
+               { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,        0 },
+               { CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+       },
+       .tuners = {
+               /* XC3028 tuner */
+               { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+       },
+       .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+       .ddr = {
+               /* Pointer to proper DDR config values provided by Terry Wu */
+               .chip_config = 0x303,
+               .refresh = 0x3bb,
+               .timing1 = 0x24220e83,
+               .timing2 = 0x1f,
+               .tune_lane = 0,
+               .initial_emrs = 0x2,
+       },
+       .gpio_init.initial_value = 0x6,
+       .gpio_init.direction = 0x7,
+       .gpio_audio_input = { .mask   = 0x7,
+                             .tuner  = 0x6, .linein = 0x2, .radio  = 0x2 },
+       .xceive_pin = 1,
+       .pci_list = cx18_pci_leadtek_dvr3100h,
+       .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
 static const struct cx18_card *cx18_card_list[] = {
        &cx18_card_hvr1600_esmt,
        &cx18_card_hvr1600_samsung,
@@ -400,6 +448,7 @@ static const struct cx18_card *cx18_card_list[] = {
        &cx18_card_cnxt_raptor_pal,
        &cx18_card_toshiba_qosmio_dvbt,
        &cx18_card_leadtek_pvr2100,
+       &cx18_card_leadtek_dvr3100h,
 };
 
 const struct cx18_card *cx18_get_card(u16 index)
index 82fc2f9d40219d3ff0075239597553a8909d930b..8e35c3aed544a3f9a1e0479b6334fac4363488ba 100644 (file)
@@ -176,8 +176,10 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx,
                return -EBUSY;
 
        if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
-           type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
-               /* We don't do VBI insertion aside from IVTV format in a PS */
+           !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS ||
+             type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD ||
+             type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) {
+               /* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */
                cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
                CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
                                "the MPEG stream\n");
index 49b1c3d7b1a81ab264a5fe3503f06b1158f76980..92026e82e10ef0349b8ac2bdbdf88d4c9aad30f8 100644 (file)
@@ -30,6 +30,7 @@
 #include "cx18-irq.h"
 #include "cx18-gpio.h"
 #include "cx18-firmware.h"
+#include "cx18-queue.h"
 #include "cx18-streams.h"
 #include "cx18-av-core.h"
 #include "cx18-scb.h"
@@ -151,7 +152,8 @@ MODULE_PARM_DESC(cardtype,
                 "\t\t\t 4 = Yuan MPC718\n"
                 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
                 "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
-                "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n"
+                "\t\t\t 7 = Leadtek WinFast PVR2100\n"
+                "\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
                 "\t\t\t 0 = Autodetect (default)\n"
                 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -312,7 +314,7 @@ static void cx18_process_eeprom(struct cx18 *cx)
        CX18_INFO("Autodetected %s\n", cx->card_name);
 
        if (tv.tuner_type == TUNER_ABSENT)
-               CX18_ERR("tveeprom cannot autodetect tuner!");
+               CX18_ERR("tveeprom cannot autodetect tuner!\n");
 
        if (cx->options.tuner == -1)
                cx->options.tuner = tv.tuner_type;
@@ -546,6 +548,40 @@ done:
        cx->card_i2c = cx->card->i2c;
 }
 
+static int __devinit cx18_create_in_workq(struct cx18 *cx)
+{
+       snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
+                cx->v4l2_dev.name);
+       cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name);
+       if (cx->in_work_queue == NULL) {
+               CX18_ERR("Unable to create incoming mailbox handler thread\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int __devinit cx18_create_out_workq(struct cx18 *cx)
+{
+       snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out",
+                cx->v4l2_dev.name);
+       cx->out_work_queue = create_workqueue(cx->out_workq_name);
+       if (cx->out_work_queue == NULL) {
+               CX18_ERR("Unable to create outgoing mailbox handler threads\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
+               cx->in_work_order[i].cx = cx;
+               cx->in_work_order[i].str = cx->epu_debug_str;
+               INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler);
+       }
+}
+
 /* Precondition: the cx18 structure has been memset to 0. Only
    the dev and instance fields have been filled in.
    No assumptions on the card type may be made here (see cx18_init_struct2
@@ -553,7 +589,7 @@ done:
  */
 static int __devinit cx18_init_struct1(struct cx18 *cx)
 {
-       int i;
+       int ret;
 
        cx->base_addr = pci_resource_start(cx->pci_dev, 0);
 
@@ -562,18 +598,18 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
        mutex_init(&cx->epu2apu_mb_lock);
        mutex_init(&cx->epu2cpu_mb_lock);
 
-       cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name);
-       if (cx->work_queue == NULL) {
-               CX18_ERR("Unable to create work hander thread\n");
-               return -ENOMEM;
-       }
+       ret = cx18_create_out_workq(cx);
+       if (ret)
+               return ret;
 
-       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
-               cx->epu_work_order[i].cx = cx;
-               cx->epu_work_order[i].str = cx->epu_debug_str;
-               INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler);
+       ret = cx18_create_in_workq(cx);
+       if (ret) {
+               destroy_workqueue(cx->out_work_queue);
+               return ret;
        }
 
+       cx18_init_in_work_orders(cx);
+
        /* start counting open_id at 1 */
        cx->open_id = 1;
 
@@ -759,17 +795,17 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
                retval = -ENODEV;
                goto err;
        }
-       if (cx18_init_struct1(cx)) {
-               retval = -ENOMEM;
+
+       retval = cx18_init_struct1(cx);
+       if (retval)
                goto err;
-       }
 
        CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
 
        /* PCI Device Setup */
        retval = cx18_setup_pci(cx, pci_dev, pci_id);
        if (retval != 0)
-               goto free_workqueue;
+               goto free_workqueues;
 
        /* map io memory */
        CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@@ -943,8 +979,9 @@ free_map:
        cx18_iounmap(cx);
 free_mem:
        release_mem_region(cx->base_addr, CX18_MEM_SIZE);
-free_workqueue:
-       destroy_workqueue(cx->work_queue);
+free_workqueues:
+       destroy_workqueue(cx->in_work_queue);
+       destroy_workqueue(cx->out_work_queue);
 err:
        if (retval == 0)
                retval = -ENODEV;
@@ -1053,11 +1090,19 @@ int cx18_init_on_first_open(struct cx18 *cx)
        return 0;
 }
 
-static void cx18_cancel_epu_work_orders(struct cx18 *cx)
+static void cx18_cancel_in_work_orders(struct cx18 *cx)
 {
        int i;
-       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++)
-               cancel_work_sync(&cx->epu_work_order[i].work);
+       for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++)
+               cancel_work_sync(&cx->in_work_order[i].work);
+}
+
+static void cx18_cancel_out_work_orders(struct cx18 *cx)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_STREAMS; i++)
+               if (&cx->streams[i].video_dev != NULL)
+                       cancel_work_sync(&cx->streams[i].out_work_order);
 }
 
 static void cx18_remove(struct pci_dev *pci_dev)
@@ -1073,15 +1118,20 @@ static void cx18_remove(struct pci_dev *pci_dev)
        if (atomic_read(&cx->tot_capturing) > 0)
                cx18_stop_all_captures(cx);
 
-       /* Interrupts */
+       /* Stop interrupts that cause incoming work to be queued */
        cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+
+       /* Incoming work can cause outgoing work, so clean up incoming first */
+       cx18_cancel_in_work_orders(cx);
+       cx18_cancel_out_work_orders(cx);
+
+       /* Stop ack interrupts that may have been needed for work to finish */
        cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
        cx18_halt_firmware(cx);
 
-       cx18_cancel_epu_work_orders(cx);
-
-       destroy_workqueue(cx->work_queue);
+       destroy_workqueue(cx->in_work_queue);
+       destroy_workqueue(cx->out_work_queue);
 
        cx18_streams_cleanup(cx, 1);
 
index ece4f281ef4254df1ec84b5bcc8676c316f84061..c6a1e907f63afd928ace5530d7a45857ccbd97a3 100644 (file)
@@ -80,8 +80,9 @@
 #define CX18_CARD_YUAN_MPC718        3 /* Yuan MPC718 */
 #define CX18_CARD_CNXT_RAPTOR_PAL     4        /* Conexant Raptor PAL */
 #define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
-#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100/DVR3100 H */
-#define CX18_CARD_LAST                       6
+#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100 */
+#define CX18_CARD_LEADTEK_DVR3100H    7 /* Leadtek WinFast DVR3100 H */
+#define CX18_CARD_LAST                       7
 
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_TS   1
@@ -254,6 +255,7 @@ struct cx18_options {
 #define CX18_F_S_INTERNAL_USE  5       /* this stream is used internally (sliced VBI processing) */
 #define CX18_F_S_STREAMOFF     7       /* signal end of stream EOS */
 #define CX18_F_S_APPL_IO        8      /* this stream is used read/written by an application */
+#define CX18_F_S_STOPPING      9       /* telling the fw to stop capturing */
 
 /* per-cx18, i_flags */
 #define CX18_F_I_LOADED_FW             0       /* Loaded firmware 1st time */
@@ -285,6 +287,7 @@ struct cx18_queue {
        struct list_head list;
        atomic_t buffers;
        u32 bytesused;
+       spinlock_t lock;
 };
 
 struct cx18_dvb {
@@ -305,7 +308,7 @@ struct cx18_scb; /* forward reference */
 
 
 #define CX18_MAX_MDL_ACKS 2
-#define CX18_MAX_EPU_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
+#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
 /* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */
 
 #define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1
@@ -313,7 +316,7 @@ struct cx18_scb; /* forward reference */
 #define CX18_F_EWO_MB_STALE \
             (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC)
 
-struct cx18_epu_work_order {
+struct cx18_in_work_order {
        struct work_struct work;
        atomic_t pending;
        struct cx18 *cx;
@@ -337,7 +340,6 @@ struct cx18_stream {
        unsigned mdl_offset;
 
        u32 id;
-       struct mutex qlock;     /* locks access to the queues */
        unsigned long s_flags;  /* status flags, see above */
        int dma;                /* can be PCI_DMA_TODEVICE,
                                   PCI_DMA_FROMDEVICE or
@@ -353,6 +355,8 @@ struct cx18_stream {
        struct cx18_queue q_busy;       /* busy buffers - in use by firmware */
        struct cx18_queue q_full;       /* full buffers - data for user apps */
 
+       struct work_struct out_work_order;
+
        /* DVB / Digital Transport */
        struct cx18_dvb dvb;
 };
@@ -568,10 +572,14 @@ struct cx18 {
        u32 sw2_irq_mask;
        u32 hw2_irq_mask;
 
-       struct workqueue_struct *work_queue;
-       struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS];
+       struct workqueue_struct *in_work_queue;
+       char in_workq_name[11]; /* "cx18-NN-in" */
+       struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS];
        char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
 
+       struct workqueue_struct *out_work_queue;
+       char out_workq_name[12]; /* "cx18-NN-out" */
+
        /* i2c */
        struct i2c_adapter i2c_adap[2];
        struct i2c_algo_bit_data i2c_algo[2];
index 3b86f57cd15af5148aa4ec0d1284c21218fdf6b9..6ea3fe623ef49470d9a900197f41a3768f440596 100644 (file)
 #include "cx18-version.h"
 #include "cx18-dvb.h"
 #include "cx18-io.h"
+#include "cx18-queue.h"
 #include "cx18-streams.h"
 #include "cx18-cards.h"
+#include "cx18-gpio.h"
 #include "s5h1409.h"
 #include "mxl5005s.h"
+#include "zl10353.h"
+#include "tuner-xc2028.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 #define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
+#define CX18_CLOCK_ENABLE2              0xc71024
+#define CX18_DMUX_CLK_MASK              0x0080
 
 static struct mxl5005s_config hauppauge_hvr1600_tuner = {
        .i2c_address     = 0xC6 >> 1,
@@ -57,7 +63,15 @@ static struct s5h1409_config hauppauge_hvr1600_config = {
        .inversion     = S5H1409_INVERSION_OFF,
        .status_mode   = S5H1409_DEMODLOCKING,
        .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
+};
 
+/* Information/confirmation of proper config values provided by Terry Wu */
+static struct zl10353_config leadtek_dvr3100h_demod = {
+       .demod_address         = 0x1e >> 1, /* Datasheet suggested straps */
+       .if2                   = 45600,     /* 4.560 MHz IF from the XC3028 */
+       .parallel_ts           = 1,         /* Not a serial TS */
+       .no_tuner              = 1,         /* XC3028 is not behind the gate */
+       .disable_i2c_gate_ctrl = 1,         /* Disable the I2C gate */
 };
 
 static int dvb_register(struct cx18_stream *stream);
@@ -98,6 +112,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
                cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
                break;
 
+       case CX18_CARD_LEADTEK_DVR3100H:
        default:
                /* Assumption - Parallel transport - Signalling
                 * undefined or default.
@@ -267,8 +282,7 @@ void cx18_dvb_unregister(struct cx18_stream *stream)
 }
 
 /* All the DVB attach calls go here, this function get's modified
- * for each new card. No other function in this file needs
- * to change.
+ * for each new card. cx18_dvb_start_feed() will also need changes.
  */
 static int dvb_register(struct cx18_stream *stream)
 {
@@ -289,6 +303,29 @@ static int dvb_register(struct cx18_stream *stream)
                        ret = 0;
                }
                break;
+       case CX18_CARD_LEADTEK_DVR3100H:
+               dvb->fe = dvb_attach(zl10353_attach,
+                                    &leadtek_dvr3100h_demod,
+                                    &cx->i2c_adap[1]);
+               if (dvb->fe != NULL) {
+                       struct dvb_frontend *fe;
+                       struct xc2028_config cfg = {
+                               .i2c_adap = &cx->i2c_adap[1],
+                               .i2c_addr = 0xc2 >> 1,
+                               .ctrl = NULL,
+                       };
+                       static struct xc2028_ctrl ctrl = {
+                               .fname   = XC2028_DEFAULT_FIRMWARE,
+                               .max_len = 64,
+                               .demod   = XC3028_FE_ZARLINK456,
+                               .type    = XC2028_AUTO,
+                       };
+
+                       fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+                       if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+                               fe->ops.tuner_ops.set_config(fe, &ctrl);
+               }
+               break;
        default:
                /* No Digital Tv Support */
                break;
@@ -299,6 +336,8 @@ static int dvb_register(struct cx18_stream *stream)
                return -1;
        }
 
+       dvb->fe->callback = cx18_reset_tuner_gpio;
+
        ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
        if (ret < 0) {
                if (dvb->fe->ops.release)
@@ -306,5 +345,16 @@ static int dvb_register(struct cx18_stream *stream)
                return ret;
        }
 
+       /*
+        * The firmware seems to enable the TS DMUX clock
+        * under various circumstances.  However, since we know we
+        * might use it, let's just turn it on ourselves here.
+        */
+       cx18_write_reg_expect(cx,
+                             (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK,
+                             CX18_CLOCK_ENABLE2,
+                             CX18_DMUX_CLK_MASK,
+                             (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK);
+
        return ret;
 }
index b3889c0b26974dd6c4f1806cb99d2a624464562d..29969c18949c707eb336b18badea0437ff04d54b 100644 (file)
@@ -265,8 +265,13 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
                 * an MPEG-2 Program Pack start code, and provide only
                 * up to that point to the user, so it's easy to insert VBI data
                 * the next time around.
+                *
+                * This will not work for an MPEG-2 TS and has only been
+                * verified by analysis to work for an MPEG-2 PS.  Helen Buus
+                * pointed out this works for the CX23416 MPEG-2 DVD compatible
+                * stream, and research indicates both the MPEG 2 SVCD and DVD
+                * stream types use an MPEG-2 PS container.
                 */
-               /* FIXME - This only works for an MPEG-2 PS, not a TS */
                /*
                 * An MPEG-2 Program Stream (PS) is a series of
                 * MPEG-2 Program Packs terminated by an
index 2226e5791e99412a4437ca73cd4bd7f59cd80796..afe46c3d4057acbf08bcb30af07552d619ae9aaf 100644 (file)
@@ -131,7 +131,7 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
  * Functions that run in a work_queue work handling context
  */
 
-static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        u32 handle, mdl_ack_count, id;
        struct cx18_mailbox *mb;
@@ -191,29 +191,30 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
                if (buf == NULL) {
                        CX18_WARN("Could not find buf %d for stream %s\n",
                                  id, s->name);
-                       /* Put as many buffers as possible back into fw use */
-                       cx18_stream_load_fw_queue(s);
                        continue;
                }
 
-               if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
-                       CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
-                                         buf->bytesused);
-                       dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
-                                        buf->bytesused);
+               CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n",
+                                 s->name, buf->bytesused);
+
+               if (s->type != CX18_ENC_STREAM_TYPE_TS)
+                       cx18_enqueue(s, buf, &s->q_full);
+               else {
+                       if (s->dvb.enabled)
+                               dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
+                                                buf->bytesused);
+                       cx18_enqueue(s, buf, &s->q_free);
                }
-               /* Put as many buffers as possible back into fw use */
-               cx18_stream_load_fw_queue(s);
-               /* Put back TS buffer, since it was removed from all queues */
-               if (s->type == CX18_ENC_STREAM_TYPE_TS)
-                       cx18_stream_put_buf_fw(s, buf);
        }
+       /* Put as many buffers as possible back into fw use */
+       cx18_stream_load_fw_queue(s);
+
        wake_up(&cx->dma_waitq);
        if (s->id != -1)
                wake_up(&s->waitq);
 }
 
-static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        char *p;
        char *str = order->str;
@@ -224,7 +225,7 @@ static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order)
                CX18_INFO("FW version: %s\n", p - 1);
 }
 
-static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        switch (order->rpu) {
        case CPU:
@@ -253,18 +254,18 @@ static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static
-void free_epu_work_order(struct cx18 *cx, struct cx18_epu_work_order *order)
+void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        atomic_set(&order->pending, 0);
 }
 
-void cx18_epu_work_handler(struct work_struct *work)
+void cx18_in_work_handler(struct work_struct *work)
 {
-       struct cx18_epu_work_order *order =
-                       container_of(work, struct cx18_epu_work_order, work);
+       struct cx18_in_work_order *order =
+                       container_of(work, struct cx18_in_work_order, work);
        struct cx18 *cx = order->cx;
        epu_cmd(cx, order);
-       free_epu_work_order(cx, order);
+       free_in_work_order(cx, order);
 }
 
 
@@ -272,7 +273,7 @@ void cx18_epu_work_handler(struct work_struct *work)
  * Functions that run in an interrupt handling context
  */
 
-static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        struct cx18_mailbox __iomem *ack_mb;
        u32 ack_irq, req;
@@ -308,7 +309,7 @@ static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
        return;
 }
 
-static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        u32 handle, mdl_ack_offset, mdl_ack_count;
        struct cx18_mailbox *mb;
@@ -334,7 +335,7 @@ static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static
-int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        u32 str_offset;
        char *str = order->str;
@@ -355,7 +356,7 @@ int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static inline
-int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        int ret = -1;
 
@@ -387,12 +388,12 @@ int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static inline
-struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx)
+struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx)
 {
        int i;
-       struct cx18_epu_work_order *order = NULL;
+       struct cx18_in_work_order *order = NULL;
 
-       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
+       for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
                /*
                 * We only need "pending" atomic to inspect its contents,
                 * and need not do a check and set because:
@@ -401,8 +402,8 @@ struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx)
                 * 2. "pending" is only set here, and we're serialized because
                 * we're called in an IRQ handler context.
                 */
-               if (atomic_read(&cx->epu_work_order[i].pending) == 0) {
-                       order = &cx->epu_work_order[i];
+               if (atomic_read(&cx->in_work_order[i].pending) == 0) {
+                       order = &cx->in_work_order[i];
                        atomic_set(&order->pending, 1);
                        break;
                }
@@ -414,7 +415,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
 {
        struct cx18_mailbox __iomem *mb;
        struct cx18_mailbox *order_mb;
-       struct cx18_epu_work_order *order;
+       struct cx18_in_work_order *order;
        int submit;
 
        switch (rpu) {
@@ -428,7 +429,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
                return;
        }
 
-       order = alloc_epu_work_order_irq(cx);
+       order = alloc_in_work_order_irq(cx);
        if (order == NULL) {
                CX18_WARN("Unable to find blank work order form to schedule "
                          "incoming mailbox command processing\n");
@@ -461,7 +462,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
         */
        submit = epu_cmd_irq(cx, order);
        if (submit > 0) {
-               queue_work(cx->work_queue, &order->work);
+               queue_work(cx->in_work_queue, &order->work);
        }
 }
 
@@ -478,9 +479,10 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
        u32 __iomem *xpu_state;
        wait_queue_head_t *waitq;
        struct mutex *mb_lock;
-       long int timeout, ret;
+       unsigned long int t0, timeout, ret;
        int i;
        char argstr[MAX_MB_ARGUMENTS*11+1];
+       DEFINE_WAIT(w);
 
        if (info == NULL) {
                CX18_WARN("unknown cmd %x\n", cmd);
@@ -562,25 +564,49 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
 
        CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n",
                          irq, info->name);
+
+       /* So we don't miss the wakeup, prepare to wait before notifying fw */
+       prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE);
        cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
 
-       ret = wait_event_timeout(
-                      *waitq,
-                      cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request),
-                      timeout);
+       t0 = jiffies;
+       ack = cx18_readl(cx, &mb->ack);
+       if (ack != req) {
+               schedule_timeout(timeout);
+               ret = jiffies - t0;
+               ack = cx18_readl(cx, &mb->ack);
+       } else {
+               ret = jiffies - t0;
+       }
 
-       if (ret == 0) {
-               /* Timed out */
+       finish_wait(waitq, &w);
+
+       if (req != ack) {
                mutex_unlock(mb_lock);
-               CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU "
-                               "acknowledgement\n",
-                               info->name, jiffies_to_msecs(timeout));
+               if (ret >= timeout) {
+                       /* Timed out */
+                       CX18_DEBUG_WARN("sending %s timed out waiting %d msecs "
+                                       "for RPU acknowledgement\n",
+                                       info->name, jiffies_to_msecs(ret));
+               } else {
+                       CX18_DEBUG_WARN("woken up before mailbox ack was ready "
+                                       "after submitting %s to RPU.  only "
+                                       "waited %d msecs on req %u but awakened"
+                                       " with unmatched ack %u\n",
+                                       info->name,
+                                       jiffies_to_msecs(ret),
+                                       req, ack);
+               }
                return -EINVAL;
        }
 
-       if (ret != timeout)
+       if (ret >= timeout)
+               CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment "
+                               "sending %s; timed out waiting %d msecs\n",
+                               info->name, jiffies_to_msecs(ret));
+       else
                CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n",
-                                 jiffies_to_msecs(timeout-ret), info->name);
+                                 jiffies_to_msecs(ret), info->name);
 
        /* Collect data returned by the XPU */
        for (i = 0; i < MAX_MB_ARGUMENTS; i++)
index ce2b6686aa005268363be2335ea61ba0910a001f..e23aaac5b280a58effb251af3df7a1acd6f1ec4d 100644 (file)
@@ -95,6 +95,6 @@ int cx18_api_func(void *priv, u32 cmd, int in, int out,
 
 void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu);
 
-void cx18_epu_work_handler(struct work_struct *work);
+void cx18_in_work_handler(struct work_struct *work);
 
 #endif
index 3046b8e74345081d30608af439ff09e17b3a331f..fa1ed7897d97abc8dc7c1c8bd5451220baa6a6ff 100644 (file)
@@ -23,8 +23,8 @@
  */
 
 #include "cx18-driver.h"
-#include "cx18-streams.h"
 #include "cx18-queue.h"
+#include "cx18-streams.h"
 #include "cx18-scb.h"
 
 void cx18_buf_swap(struct cx18_buffer *buf)
@@ -53,13 +53,13 @@ struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
                buf->skipped = 0;
        }
 
-       mutex_lock(&s->qlock);
-
        /* q_busy is restricted to a max buffer count imposed by firmware */
        if (q == &s->q_busy &&
            atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM)
                q = &s->q_free;
 
+       spin_lock(&q->lock);
+
        if (to_front)
                list_add(&buf->list, &q->list); /* LIFO */
        else
@@ -67,7 +67,7 @@ struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
        q->bytesused += buf->bytesused - buf->readpos;
        atomic_inc(&q->buffers);
 
-       mutex_unlock(&s->qlock);
+       spin_unlock(&q->lock);
        return q;
 }
 
@@ -75,7 +75,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
 {
        struct cx18_buffer *buf = NULL;
 
-       mutex_lock(&s->qlock);
+       spin_lock(&q->lock);
        if (!list_empty(&q->list)) {
                buf = list_first_entry(&q->list, struct cx18_buffer, list);
                list_del_init(&buf->list);
@@ -83,7 +83,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
                buf->skipped = 0;
                atomic_dec(&q->buffers);
        }
-       mutex_unlock(&s->qlock);
+       spin_unlock(&q->lock);
        return buf;
 }
 
@@ -94,9 +94,23 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
        struct cx18_buffer *buf;
        struct cx18_buffer *tmp;
        struct cx18_buffer *ret = NULL;
-
-       mutex_lock(&s->qlock);
+       LIST_HEAD(sweep_up);
+
+       /*
+        * We don't have to acquire multiple q locks here, because we are
+        * serialized by the single threaded work handler.
+        * Buffers from the firmware will thus remain in order as
+        * they are moved from q_busy to q_full or to the dvb ring buffer.
+        */
+       spin_lock(&s->q_busy.lock);
        list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) {
+               /*
+                * We should find what the firmware told us is done,
+                * right at the front of the queue.  If we don't, we likely have
+                * missed a buffer done message from the firmware.
+                * Once we skip a buffer repeatedly, relative to the size of
+                * q_busy, we have high confidence we've missed it.
+                */
                if (buf->id != id) {
                        buf->skipped++;
                        if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) {
@@ -105,38 +119,41 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
                                          "times - it must have dropped out of "
                                          "rotation\n", s->name, buf->id,
                                          buf->skipped);
-                               /* move it to q_free */
-                               list_move_tail(&buf->list, &s->q_free.list);
-                               buf->bytesused = buf->readpos = buf->b_flags =
-                                       buf->skipped = 0;
+                               /* Sweep it up to put it back into rotation */
+                               list_move_tail(&buf->list, &sweep_up);
                                atomic_dec(&s->q_busy.buffers);
-                               atomic_inc(&s->q_free.buffers);
                        }
                        continue;
                }
-
-               buf->bytesused = bytesused;
-               /* Sync the buffer before we release the qlock */
-               cx18_buf_sync_for_cpu(s, buf);
-               if (s->type == CX18_ENC_STREAM_TYPE_TS) {
-                       /*
-                        * TS doesn't use q_full.  As we pull the buffer off of
-                        * the queue here, the caller will have to put it back.
-                        */
-                       list_del_init(&buf->list);
-               } else {
-                       /* Move buffer from q_busy to q_full */
-                       list_move_tail(&buf->list, &s->q_full.list);
-                       set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
-                       s->q_full.bytesused += buf->bytesused;
-                       atomic_inc(&s->q_full.buffers);
-               }
+               /*
+                * We pull the desired buffer off of the queue here.  Something
+                * will have to put it back on a queue later.
+                */
+               list_del_init(&buf->list);
                atomic_dec(&s->q_busy.buffers);
-
                ret = buf;
                break;
        }
-       mutex_unlock(&s->qlock);
+       spin_unlock(&s->q_busy.lock);
+
+       /*
+        * We found the buffer for which we were looking.  Get it ready for
+        * the caller to put on q_full or in the dvb ring buffer.
+        */
+       if (ret != NULL) {
+               ret->bytesused = bytesused;
+               ret->skipped = 0;
+               /* readpos and b_flags were 0'ed when the buf went on q_busy */
+               cx18_buf_sync_for_cpu(s, ret);
+               if (s->type != CX18_ENC_STREAM_TYPE_TS)
+                       set_bit(CX18_F_B_NEED_BUF_SWAP, &ret->b_flags);
+       }
+
+       /* Put any buffers the firmware is ignoring back into normal rotation */
+       list_for_each_entry_safe(buf, tmp, &sweep_up, list) {
+               list_del_init(&buf->list);
+               cx18_enqueue(s, buf, &s->q_free);
+       }
        return ret;
 }
 
@@ -148,7 +165,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
        if (q == &s->q_free)
                return;
 
-       mutex_lock(&s->qlock);
+       spin_lock(&q->lock);
        while (!list_empty(&q->list)) {
                buf = list_first_entry(&q->list, struct cx18_buffer, list);
                list_move_tail(&buf->list, &s->q_free.list);
@@ -156,7 +173,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
                atomic_inc(&s->q_free.buffers);
        }
        cx18_queue_init(q);
-       mutex_unlock(&s->qlock);
+       spin_unlock(&q->lock);
 }
 
 void cx18_flush_queues(struct cx18_stream *s)
index 0932b76b2373a76022274e5163c1976c5107191c..54d248e16d85e882d0f1d757c8111389df10b73d 100644 (file)
@@ -116,12 +116,16 @@ static void cx18_stream_init(struct cx18 *cx, int type)
        s->buffers = cx->stream_buffers[type];
        s->buf_size = cx->stream_buf_size[type];
 
-       mutex_init(&s->qlock);
        init_waitqueue_head(&s->waitq);
        s->id = -1;
+       spin_lock_init(&s->q_free.lock);
        cx18_queue_init(&s->q_free);
+       spin_lock_init(&s->q_busy.lock);
        cx18_queue_init(&s->q_busy);
+       spin_lock_init(&s->q_full.lock);
        cx18_queue_init(&s->q_full);
+
+       INIT_WORK(&s->out_work_order, cx18_out_work_handler);
 }
 
 static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -367,9 +371,14 @@ static void cx18_vbi_setup(struct cx18_stream *s)
                 * Tell the encoder to capture 21-4+1=18 lines per field,
                 * since we want lines 10 through 21.
                 *
-                * FIXME - revisit for 625/50 systems
+                * For 625/50 systems, according to the VIP 2 & BT.656 std:
+                * The EAV RP code's Field bit toggles on line 1, a few lines
+                * after the Vertcal Blank bit has already toggled.
+                * (We've actually set the digitizer so that the Field bit
+                * toggles on line 2.) Tell the encoder to capture 23-2+1=22
+                * lines per field, since we want lines 6 through 23.
                 */
-               lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38;
+               lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2;
        }
 
        data[0] = s->handle;
@@ -431,14 +440,16 @@ static void cx18_vbi_setup(struct cx18_stream *s)
        cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
 }
 
-struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
-                                         struct cx18_buffer *buf)
+static
+struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s,
+                                          struct cx18_buffer *buf)
 {
        struct cx18 *cx = s->cx;
        struct cx18_queue *q;
 
        /* Don't give it to the firmware, if we're not running a capture */
        if (s->handle == CX18_INVALID_TASK_HANDLE ||
+           test_bit(CX18_F_S_STOPPING, &s->s_flags) ||
            !test_bit(CX18_F_S_STREAMING, &s->s_flags))
                return cx18_enqueue(s, buf, &s->q_free);
 
@@ -453,7 +464,8 @@ struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
        return q;
 }
 
-void cx18_stream_load_fw_queue(struct cx18_stream *s)
+static
+void _cx18_stream_load_fw_queue(struct cx18_stream *s)
 {
        struct cx18_queue *q;
        struct cx18_buffer *buf;
@@ -467,11 +479,19 @@ void cx18_stream_load_fw_queue(struct cx18_stream *s)
                buf = cx18_dequeue(s, &s->q_free);
                if (buf == NULL)
                        break;
-               q = cx18_stream_put_buf_fw(s, buf);
+               q = _cx18_stream_put_buf_fw(s, buf);
        } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM
                 && q == &s->q_busy);
 }
 
+void cx18_out_work_handler(struct work_struct *work)
+{
+       struct cx18_stream *s =
+                        container_of(work, struct cx18_stream, out_work_order);
+
+       _cx18_stream_load_fw_queue(s);
+}
+
 int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 {
        u32 data[MAX_MB_ARGUMENTS];
@@ -600,19 +620,20 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 
        /* Init all the cpu_mdls for this stream */
        cx18_flush_queues(s);
-       mutex_lock(&s->qlock);
+       spin_lock(&s->q_free.lock);
        list_for_each_entry(buf, &s->q_free.list, list) {
                cx18_writel(cx, buf->dma_handle,
                                        &cx->scb->cpu_mdl[buf->id].paddr);
                cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
        }
-       mutex_unlock(&s->qlock);
-       cx18_stream_load_fw_queue(s);
+       spin_unlock(&s->q_free.lock);
+       _cx18_stream_load_fw_queue(s);
 
        /* begin_capture */
        if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
                CX18_DEBUG_WARN("Error starting capture!\n");
                /* Ensure we're really not capturing before releasing MDLs */
+               set_bit(CX18_F_S_STOPPING, &s->s_flags);
                if (s->type == CX18_ENC_STREAM_TYPE_MPG)
                        cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
                else
@@ -622,6 +643,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
                cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
                s->handle = CX18_INVALID_TASK_HANDLE;
+               clear_bit(CX18_F_S_STOPPING, &s->s_flags);
                if (atomic_read(&cx->tot_capturing) == 0) {
                        set_bit(CX18_F_I_EOS, &cx->i_flags);
                        cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
@@ -666,6 +688,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
        if (atomic_read(&cx->tot_capturing) == 0)
                return 0;
 
+       set_bit(CX18_F_S_STOPPING, &s->s_flags);
        if (s->type == CX18_ENC_STREAM_TYPE_MPG)
                cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
        else
@@ -689,6 +712,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
 
        cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
        s->handle = CX18_INVALID_TASK_HANDLE;
+       clear_bit(CX18_F_S_STOPPING, &s->s_flags);
 
        if (atomic_read(&cx->tot_capturing) > 0)
                return 0;
index 420e0a172945e7c6d63f5e6bf9e62f50be2e63be..1afc3fd9d822539317801a747c58ff39e84dbb9a 100644 (file)
@@ -28,10 +28,24 @@ int cx18_streams_setup(struct cx18 *cx);
 int cx18_streams_register(struct cx18 *cx);
 void cx18_streams_cleanup(struct cx18 *cx, int unregister);
 
+/* Related to submission of buffers to firmware */
+static inline void cx18_stream_load_fw_queue(struct cx18_stream *s)
+{
+       struct cx18 *cx = s->cx;
+       queue_work(cx->out_work_queue, &s->out_work_order);
+}
+
+static inline void cx18_stream_put_buf_fw(struct cx18_stream *s,
+                                         struct cx18_buffer *buf)
+{
+       /* Put buf on q_free; the out work handler will move buf(s) to q_busy */
+       cx18_enqueue(s, buf, &s->q_free);
+       cx18_stream_load_fw_queue(s);
+}
+
+void cx18_out_work_handler(struct work_struct *work);
+
 /* Capture related */
-void cx18_stream_load_fw_queue(struct cx18_stream *s);
-struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
-                                         struct cx18_buffer *buf);
 int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
 int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
 
index bd9bd44da791a3df585609523574199294520384..45494b094e7fc568196eb51f2e0a90c92def7165 100644 (file)
@@ -24,7 +24,7 @@
 
 #define CX18_DRIVER_NAME "cx18"
 #define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 1
+#define CX18_DRIVER_VERSION_MINOR 2
 #define CX18_DRIVER_VERSION_PATCHLEVEL 0
 
 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
index 1be3881be991f05ffe546add717b859d86acdf6e..6a9464079b4cf7bb2161f0b1998d421bfbbbbc99 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 
index c8a32b1b53812654f3442939d2e14b7571087a28..63d2239fd324e14e3104b16615a7c5b2e9bed9d7 100644 (file)
@@ -281,12 +281,12 @@ static void cx231xx_config_tuner(struct cx231xx *dev)
 }
 
 /* ----------------------------------------------------------------------- */
-void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir)
+void cx231xx_register_i2c_ir(struct cx231xx *dev)
 {
-       if (disable_ir) {
-               ir->get_key = NULL;
+       if (disable_ir)
                return;
-       }
+
+       /* REVISIT: instantiate IR device */
 
        /* detect & configure */
        switch (dev->model) {
index b4a03d813e00d7b9c3001bc52233bb48e0556c87..33219dc4d64987e640f109f853ec6a8b30159cc7 100644 (file)
@@ -424,34 +424,6 @@ static u32 functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
 }
 
-/*
- * attach_inform()
- * gets called when a device attaches to the i2c bus
- * does some basic configuration
- */
-static int attach_inform(struct i2c_client *client)
-{
-       struct cx231xx_i2c *bus = i2c_get_adapdata(client->adapter);
-       struct cx231xx *dev = bus->dev;
-
-       switch (client->addr << 1) {
-       case 0x8e:
-               {
-                       struct IR_i2c *ir = i2c_get_clientdata(client);
-                       dprintk1(1, "attach_inform: IR detected (%s).\n",
-                                ir->phys);
-                       cx231xx_set_ir(dev, ir);
-                       break;
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
 static struct i2c_algorithm cx231xx_algo = {
        .master_xfer = cx231xx_i2c_xfer,
        .functionality = functionality,
@@ -462,7 +434,6 @@ static struct i2c_adapter cx231xx_adap_template = {
        .name = "cx231xx",
        .id = I2C_HW_B_CX231XX,
        .algo = &cx231xx_algo,
-       .client_register = attach_inform,
 };
 
 static struct i2c_client cx231xx_client_template = {
@@ -537,6 +508,9 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus)
        if (0 == bus->i2c_rc) {
                if (i2c_scan)
                        cx231xx_do_i2c_scan(dev, &bus->i2c_client);
+
+               /* Instantiate the IR receiver device, if present */
+               cx231xx_register_i2c_ir(dev);
        } else
                cx231xx_warn("%s: i2c bus %d register FAILED\n",
                             dev->name, bus->nr);
index 97e304c3c799ba81106d5836e6c5c1c234348244..48f22fa38e6cc7a527256227442ab331b4466319 100644 (file)
@@ -36,7 +36,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 
 #define i2cdprintk(fmt, arg...) \
        if (ir_debug) { \
-               printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
        }
 
 #define dprintk(fmt, arg...) \
index 94180526909c3d8a2c3f05a288dee7875e921b2a..e97b8023a6557a8fe15c39c921b0c36038733730 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 
index aa4a23ef491a3341e2851cc6429a25345f9fbbc6..e38eb2d425f78fdfcb03976973e1c445850705d3 100644 (file)
@@ -738,7 +738,7 @@ extern void cx231xx_card_setup(struct cx231xx *dev);
 extern struct cx231xx_board cx231xx_boards[];
 extern struct usb_device_id cx231xx_id_table[];
 extern const unsigned int cx231xx_bcount;
-void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir);
+void cx231xx_register_i2c_ir(struct cx231xx *dev);
 int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
 
 /* Provided by cx231xx-input.c */
index 9a6536998d904348fb3a0ee5377c18363766de99..08582e58bdbf368529099eb249fb77eaab9038cb 100644 (file)
@@ -312,7 +312,7 @@ static void netup_read_ci_status(struct work_struct *work)
                "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0],
                buf[32]);
 
-       if (buf[0] && 1)
+       if (buf[0] & 1)
                state->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
                        DVB_CA_EN50221_POLL_CAM_READY;
        else
index 6f5df90af93ef2a89f2c4bc48bf0c64640b89dea..2943bfd32a94a4b74acb19d6a9076abd7e1d3388 100644 (file)
@@ -1742,7 +1742,6 @@ static struct video_device *cx23885_video_dev_alloc(
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       vfd->minor   = -1;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
                type, cx23885_boards[tsport->dev->board].name);
        vfd->parent  = &pci->dev;
index 6d6293f7d428e6fe501f2c2b4d3d02727dc1132a..ce29b5e34a11329f58e5fca573205d8316876ff7 100644 (file)
@@ -181,6 +181,26 @@ struct cx23885_board cx23885_boards[] = {
                .portb          = CX23885_MPEG_DVB,
                .portc          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_HAUPPAUGE_HVR1270] = {
+               .name           = "Hauppauge WinTV-HVR1270",
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_HAUPPAUGE_HVR1275] = {
+               .name           = "Hauppauge WinTV-HVR1275",
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_HAUPPAUGE_HVR1255] = {
+               .name           = "Hauppauge WinTV-HVR1255",
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_HAUPPAUGE_HVR1210] = {
+               .name           = "Hauppauge WinTV-HVR1210",
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_MYGICA_X8506] = {
+               .name           = "Mygica X8506 DMB-TH",
+               .portb          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -280,6 +300,30 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x1b55,
                .subdevice = 0x2a2c,
                .card      = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2211,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1270,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2215,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2251,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2291,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2295,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+       }, {
+               .subvendor = 0x14f1,
+               .subdevice = 0x8651,
+               .card      = CX23885_BOARD_MYGICA_X8506,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -321,6 +365,42 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
 
        /* Make sure we support the board model */
        switch (tv.model) {
+       case 22001:
+               /* WinTV-HVR1270 (PCIe, Retail, half height)
+                * ATSC/QAM and basic analog, IR Blast */
+       case 22009:
+               /* WinTV-HVR1210 (PCIe, Retail, half height)
+                * DVB-T and basic analog, IR Blast */
+       case 22011:
+               /* WinTV-HVR1270 (PCIe, Retail, half height)
+                * ATSC/QAM and basic analog, IR Recv */
+       case 22019:
+               /* WinTV-HVR1210 (PCIe, Retail, half height)
+                * DVB-T and basic analog, IR Recv */
+       case 22021:
+               /* WinTV-HVR1275 (PCIe, Retail, half height)
+                * ATSC/QAM and basic analog, IR Recv */
+       case 22029:
+               /* WinTV-HVR1210 (PCIe, Retail, half height)
+                * DVB-T and basic analog, IR Recv */
+       case 22101:
+               /* WinTV-HVR1270 (PCIe, Retail, full height)
+                * ATSC/QAM and basic analog, IR Blast */
+       case 22109:
+               /* WinTV-HVR1210 (PCIe, Retail, full height)
+                * DVB-T and basic analog, IR Blast */
+       case 22111:
+               /* WinTV-HVR1270 (PCIe, Retail, full height)
+                * ATSC/QAM and basic analog, IR Recv */
+       case 22119:
+               /* WinTV-HVR1210 (PCIe, Retail, full height)
+                * DVB-T and basic analog, IR Recv */
+       case 22121:
+               /* WinTV-HVR1275 (PCIe, Retail, full height)
+                * ATSC/QAM and basic analog, IR Recv */
+       case 22129:
+               /* WinTV-HVR1210 (PCIe, Retail, full height)
+                * DVB-T and basic analog, IR Recv */
        case 71009:
                /* WinTV-HVR1200 (PCIe, Retail, full height)
                 * DVB-T and basic analog */
@@ -619,6 +699,30 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                /* enable irq */
                cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
+               /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */
+               /* GPIO-6 I2C Gate which can isolate the demod from the bus */
+               /* GPIO-9 Demod reset */
+
+               /* Put the parts into reset and back */
+               cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1);
+               cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5);
+               cx23885_gpio_clear(dev, GPIO_9);
+               mdelay(20);
+               cx23885_gpio_set(dev, GPIO_9);
+               break;
+       case CX23885_BOARD_MYGICA_X8506:
+               /* GPIO-1 reset XC5000 */
+               /* GPIO-2 reset LGS8GL5 */
+               cx_set(GP0_IO, 0x00060000);
+               cx_clear(GP0_IO, 0x00000006);
+               mdelay(100);
+               cx_set(GP0_IO, 0x00060006);
+               mdelay(100);
+               break;
        }
 }
 
@@ -631,6 +735,10 @@ int cx23885_ir_init(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
        case CX23885_BOARD_HAUPPAUGE_HVR1200:
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
                /* FIXME: Implement me */
                break;
        case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
@@ -666,6 +774,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
        case CX23885_BOARD_HAUPPAUGE_HVR1200:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
                if (dev->i2c_bus[0].i2c_rc == 0)
                        hauppauge_eeprom(dev, eeprom+0xc0);
                break;
@@ -714,6 +826,11 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
+       case CX23885_BOARD_MYGICA_X8506:
+               ts1->gen_ctrl_val  = 0x5; /* Parallel */
+               ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -723,6 +840,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
        default:
                ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
index beda42925ce761c961e7b08673a195cd6e6017fe..bf7bb1c412fb6e3735daf7dee875fa1b1a705ac0 100644 (file)
@@ -1700,9 +1700,13 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
        }
 
        if (cx23885_boards[dev->board].cimax > 0 &&
-               ((pci_status & PCI_MSK_GPIO0) || (pci_status & PCI_MSK_GPIO1)))
-               /* handled += cx23885_irq_gpio(dev, pci_status); */
-               handled += netup_ci_slot_status(dev, pci_status);
+               ((pci_status & PCI_MSK_GPIO0) ||
+                       (pci_status & PCI_MSK_GPIO1))) {
+
+               if (cx23885_boards[dev->board].cimax > 0)
+                       handled += netup_ci_slot_status(dev, pci_status);
+
+       }
 
        if (ts1_status) {
                if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
@@ -1729,6 +1733,88 @@ out:
        return IRQ_RETVAL(handled);
 }
 
+static inline int encoder_on_portb(struct cx23885_dev *dev)
+{
+       return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER;
+}
+
+static inline int encoder_on_portc(struct cx23885_dev *dev)
+{
+       return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER;
+}
+
+/* Mask represents 32 different GPIOs, GPIO's are split into multiple
+ * registers depending on the board configuration (and whether the
+ * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will
+ * be pushed into the correct hardware register, regardless of the
+ * physical location. Certain registers are shared so we sanity check
+ * and report errors if we think we're tampering with a GPIo that might
+ * be assigned to the encoder (and used for the host bus).
+ *
+ * GPIO  2 thru  0 - On the cx23885 bridge
+ * GPIO 18 thru  3 - On the cx23417 host bus interface
+ * GPIO 23 thru 19 - On the cx25840 a/v core
+ */
+void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask)
+{
+       if (mask & 0x7)
+               cx_set(GP0_IO, mask & 0x7);
+
+       if (mask & 0x0007fff8) {
+               if (encoder_on_portb(dev) || encoder_on_portc(dev))
+                       printk(KERN_ERR
+                               "%s: Setting GPIO on encoder ports\n",
+                               dev->name);
+               cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3);
+       }
+
+       /* TODO: 23-19 */
+       if (mask & 0x00f80000)
+               printk(KERN_INFO "%s: Unsupported\n", dev->name);
+}
+
+void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask)
+{
+       if (mask & 0x00000007)
+               cx_clear(GP0_IO, mask & 0x7);
+
+       if (mask & 0x0007fff8) {
+               if (encoder_on_portb(dev) || encoder_on_portc(dev))
+                       printk(KERN_ERR
+                               "%s: Clearing GPIO moving on encoder ports\n",
+                               dev->name);
+               cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3);
+       }
+
+       /* TODO: 23-19 */
+       if (mask & 0x00f80000)
+               printk(KERN_INFO "%s: Unsupported\n", dev->name);
+}
+
+void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
+{
+       if ((mask & 0x00000007) && asoutput)
+               cx_set(GP0_IO, (mask & 0x7) << 16);
+       else if ((mask & 0x00000007) && !asoutput)
+               cx_clear(GP0_IO, (mask & 0x7) << 16);
+
+       if (mask & 0x0007fff8) {
+               if (encoder_on_portb(dev) || encoder_on_portc(dev))
+                       printk(KERN_ERR
+                               "%s: Enabling GPIO on encoder ports\n",
+                               dev->name);
+       }
+
+       /* MC417_OEN is active low for output, write 1 for an input */
+       if ((mask & 0x0007fff8) && asoutput)
+               cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3);
+
+       else if ((mask & 0x0007fff8) && !asoutput)
+               cx_set(MC417_OEN, (mask & 0x7fff8) >> 3);
+
+       /* TODO: 23-19 */
+}
+
 static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
                                     const struct pci_device_id *pci_id)
 {
index 1dc070da8652b8bcc5fdca72cfae39760944fe65..e236df23370ea52f350fcb7e52e50aead5a56191 100644 (file)
 #include "lnbh24.h"
 #include "cx24116.h"
 #include "cimax2.h"
+#include "lgs8gxx.h"
 #include "netup-eeprom.h"
 #include "netup-init.h"
+#include "lgdt3305.h"
 
 static unsigned int debug;
 
@@ -122,7 +124,22 @@ static struct tda10048_config hauppauge_hvr1200_config = {
        .demod_address    = 0x10 >> 1,
        .output_mode      = TDA10048_SERIAL_OUTPUT,
        .fwbulkwritelen   = TDA10048_BULKWRITE_200,
-       .inversion        = TDA10048_INVERSION_ON
+       .inversion        = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_3300,
+       .dtv7_if_freq_khz = TDA10048_IF_3800,
+       .dtv8_if_freq_khz = TDA10048_IF_4300,
+       .clk_freq_khz     = TDA10048_CLK_16000,
+};
+
+static struct tda10048_config hauppauge_hvr1210_config = {
+       .demod_address    = 0x10 >> 1,
+       .output_mode      = TDA10048_SERIAL_OUTPUT,
+       .fwbulkwritelen   = TDA10048_BULKWRITE_200,
+       .inversion        = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_3300,
+       .dtv7_if_freq_khz = TDA10048_IF_3500,
+       .dtv8_if_freq_khz = TDA10048_IF_4000,
+       .clk_freq_khz     = TDA10048_CLK_16000,
 };
 
 static struct s5h1409_config hauppauge_ezqam_config = {
@@ -194,6 +211,16 @@ static struct s5h1411_config dvico_s5h1411_config = {
        .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
+static struct s5h1411_config hcw_s5h1411_config = {
+       .output_mode   = S5H1411_SERIAL_OUTPUT,
+       .gpio          = S5H1411_GPIO_OFF,
+       .vsb_if        = S5H1411_IF_44000,
+       .qam_if        = S5H1411_IF_4000,
+       .inversion     = S5H1411_INVERSION_ON,
+       .status_mode   = S5H1411_DEMODLOCKING,
+       .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
 static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
        .i2c_address      = 0x61,
        .if_khz           = 5380,
@@ -224,6 +251,32 @@ static struct tda18271_config hauppauge_hvr1200_tuner_config = {
        .gate    = TDA18271_GATE_ANALOG,
 };
 
+static struct tda18271_config hauppauge_hvr1210_tuner_config = {
+       .gate    = TDA18271_GATE_DIGITAL,
+};
+
+static struct tda18271_std_map hauppauge_hvr127x_std_map = {
+       .atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+                     .if_lvl = 1, .rfagc_top = 0x58 },
+       .qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+                     .if_lvl = 1, .rfagc_top = 0x58 },
+};
+
+static struct tda18271_config hauppauge_hvr127x_config = {
+       .std_map = &hauppauge_hvr127x_std_map,
+};
+
+static struct lgdt3305_config hauppauge_lgdt3305_config = {
+       .i2c_addr           = 0x0e,
+       .mpeg_mode          = LGDT3305_MPEG_SERIAL,
+       .tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+       .tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 1,
+       .qam_if_khz         = 4000,
+       .vsb_if_khz         = 3250,
+};
+
 static struct dibx000_agc_config xc3028_agc_config = {
        BAND_VHF | BAND_UHF,    /* band_caps */
 
@@ -368,10 +421,29 @@ static struct cx24116_config dvbworld_cx24116_config = {
        .demod_address = 0x05,
 };
 
+static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = {
+       .prod = LGS8GXX_PROD_LGS8GL5,
+       .demod_address = 0x19,
+       .serial_ts = 0,
+       .ts_clk_pol = 1,
+       .ts_clk_gated = 1,
+       .if_clk_freq = 30400, /* 30.4 MHz */
+       .if_freq = 5380, /* 5.38 MHz */
+       .if_neg_center = 1,
+       .ext_adc = 0,
+       .adc_signed = 0,
+       .if_neg_edge = 0,
+};
+
+static struct xc5000_config mygica_x8506_xc5000_config = {
+       .i2c_address = 0x61,
+       .if_khz = 5380,
+};
+
 static int dvb_register(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
-       struct cx23885_i2c *i2c_bus = NULL;
+       struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
        struct videobuf_dvb_frontend *fe0;
        int ret;
 
@@ -396,6 +468,29 @@ static int dvb_register(struct cx23885_tsport *port)
                                   &hauppauge_generic_tunerconfig, 0);
                }
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+               i2c_bus = &dev->i2c_bus[0];
+               fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
+                                              &hauppauge_lgdt3305_config,
+                                              &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                                  0x60, &dev->i2c_bus[1].i2c_adap,
+                                  &hauppauge_hvr127x_config);
+               }
+               break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+               i2c_bus = &dev->i2c_bus[0];
+               fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+                                              &hcw_s5h1411_config,
+                                              &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                                  0x60, &dev->i2c_bus[1].i2c_adap,
+                                  &hauppauge_tda18271_config);
+               }
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
                i2c_bus = &dev->i2c_bus[0];
                switch (alt_tuner) {
@@ -496,6 +591,17 @@ static int dvb_register(struct cx23885_tsport *port)
                                &hauppauge_hvr1200_tuner_config);
                }
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
+               i2c_bus = &dev->i2c_bus[0];
+               fe0->dvb.frontend = dvb_attach(tda10048_attach,
+                       &hauppauge_hvr1210_config,
+                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                               0x60, &dev->i2c_bus[1].i2c_adap,
+                               &hauppauge_hvr1210_tuner_config);
+               }
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
                i2c_bus = &dev->i2c_bus[0];
                fe0->dvb.frontend = dvb_attach(dib7000p_attach,
@@ -659,6 +765,19 @@ static int dvb_register(struct cx23885_tsport *port)
                        break;
                }
                break;
+       case CX23885_BOARD_MYGICA_X8506:
+               i2c_bus = &dev->i2c_bus[0];
+               i2c_bus2 = &dev->i2c_bus[1];
+               fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+                       &mygica_x8506_lgs8gl5_config,
+                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(xc5000_attach,
+                               fe0->dvb.frontend,
+                               &i2c_bus2->i2c_adap,
+                               &mygica_x8506_xc5000_config);
+               }
+               break;
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
index 3421bd12056a95ee58a4604ca380354f4ccb444c..384dec34134fe56ef6298909fa6a633a0c9bec4b 100644 (file)
@@ -357,6 +357,18 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
                printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
                        dev->name, bus->nr);
 
+       /* Instantiate the IR receiver device, if present */
+       if (0 == bus->i2c_rc) {
+               struct i2c_board_info info;
+               const unsigned short addr_list[] = {
+                       0x6b, I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&bus->i2c_adap, &info, addr_list);
+       }
+
        return bus->i2c_rc;
 }
 
index 68068c6d098729c53b43d11c30f83c241e6d5cc4..66bbd2e711057fba20904513ca102640dc425331 100644 (file)
@@ -796,6 +796,7 @@ static unsigned int video_poll(struct file *file,
 {
        struct cx23885_fh *fh = file->private_data;
        struct cx23885_buffer *buf;
+       unsigned int rc = POLLERR;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
                if (!res_get(fh->dev, fh, RESOURCE_VBI))
@@ -803,23 +804,28 @@ static unsigned int video_poll(struct file *file,
                return videobuf_poll_stream(file, &fh->vbiq, wait);
        }
 
+       mutex_lock(&fh->vidq.vb_lock);
        if (res_check(fh, RESOURCE_VIDEO)) {
                /* streaming capture */
                if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
+                       goto done;
                buf = list_entry(fh->vidq.stream.next,
                        struct cx23885_buffer, vb.stream);
        } else {
                /* read() capture */
                buf = (struct cx23885_buffer *)fh->vidq.read_buf;
                if (NULL == buf)
-                       return POLLERR;
+                       goto done;
        }
        poll_wait(file, &buf->vb.done, wait);
        if (buf->vb.state == VIDEOBUF_DONE ||
            buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
+               rc =  POLLIN|POLLRDNORM;
+       else
+               rc = 0;
+done:
+       mutex_unlock(&fh->vidq.vb_lock);
+       return rc;
 }
 
 static int video_release(struct file *file)
index 85642831ea8e935ffc96b1457aeaade824c7b598..1a2ac518a3f1ae21362ae8694a4289d1d4c78cba 100644 (file)
 #define CX23885_BOARD_TEVII_S470               15
 #define CX23885_BOARD_DVBWORLD_2005            16
 #define CX23885_BOARD_NETUP_DUAL_DVBS2_CI      17
+#define CX23885_BOARD_HAUPPAUGE_HVR1270        18
+#define CX23885_BOARD_HAUPPAUGE_HVR1275        19
+#define CX23885_BOARD_HAUPPAUGE_HVR1255        20
+#define CX23885_BOARD_HAUPPAUGE_HVR1210        21
+#define CX23885_BOARD_MYGICA_X8506             22
+
+#define GPIO_0 0x00000001
+#define GPIO_1 0x00000002
+#define GPIO_2 0x00000004
+#define GPIO_3 0x00000008
+#define GPIO_4 0x00000010
+#define GPIO_5 0x00000020
+#define GPIO_6 0x00000040
+#define GPIO_7 0x00000080
+#define GPIO_8 0x00000100
+#define GPIO_9 0x00000200
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
@@ -422,6 +438,11 @@ extern int cx23885_restart_queue(struct cx23885_tsport *port,
 extern void cx23885_wakeup(struct cx23885_tsport *port,
                           struct cx23885_dmaqueue *q, u32 count);
 
+extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask,
+       int asoutput);
+
 
 /* ----------------------------------------------------------- */
 /* cx23885-cards.c                                             */
index b06b1275a9eca270d157f6f8bdaa3839535c61cd..5b7e26761f0a78006ebfd064dbc667db4edcc8b7 100644 (file)
@@ -1,5 +1,5 @@
 cx88xx-objs    := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
-                  cx88-input.o
+                  cx88-dsp.o cx88-input.o
 cx8800-objs    := cx88-video.o cx88-vbi.o
 cx8802-objs    := cx88-mpeg.o
 
index 0ccdf36626e30a0f30d47e7bb7fb44c2bfe04833..5a67445dd6ed900f465f3fb2334a2c5346e5f419 100644 (file)
@@ -871,7 +871,7 @@ static struct pci_driver cx88_audio_pci_driver = {
        .name     = "cx88_audio",
        .id_table = cx88_audio_pci_tbl,
        .probe    = cx88_audio_initdev,
-       .remove   = cx88_audio_finidev,
+       .remove   = __devexit_p(cx88_audio_finidev),
 };
 
 /****************************************************************************
@@ -881,7 +881,7 @@ static struct pci_driver cx88_audio_pci_driver = {
 /*
  * module init
  */
-static int cx88_audio_init(void)
+static int __init cx88_audio_init(void)
 {
        printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
               (CX88_VERSION_CODE >> 16) & 0xff,
@@ -897,9 +897,8 @@ static int cx88_audio_init(void)
 /*
  * module remove
  */
-static void cx88_audio_fini(void)
+static void __exit cx88_audio_fini(void)
 {
-
        pci_unregister_driver(&cx88_audio_pci_driver);
 }
 
index 6bbbfc66bb4bf2ac84be1fc56ecf5c7c0f8cc145..94b7a52629d057c0bd5295ec7783388026484eae 100644 (file)
@@ -1969,6 +1969,54 @@ static const struct cx88_board cx88_boards[] = {
                },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_HAUPPAUGE_IRONLY] = {
+               .name           = "Hauppauge WinTV-IR Only",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [CX88_BOARD_WINFAST_DTV1800H] = {
+               .name           = "Leadtek WinFast DTV1800 Hybrid",
+               .tuner_type     = TUNER_XC2028,
+               .radio_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61,
+               .radio_addr     = 0x61,
+               /*
+                * GPIO setting
+                *
+                *  2: mute (0=off,1=on)
+                * 12: tuner reset pin
+                * 13: audio source (0=tuner audio,1=line in)
+                * 14: FM (0=on,1=off ???)
+                */
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6040,       /* pin 13 = 0, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               } },
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6000,       /* pin 13 = 0, pin 14 = 0 */
+                       .gpio2  = 0x0000,
+               },
+               .mpeg           = CX88_MPEG_DVB,
+       },
 };
 
 /* ------------------------------------------------------------------ */
@@ -2382,6 +2430,14 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x153b,
                .subdevice = 0x1177,
                .card      = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x9290,
+               .card      = CX88_BOARD_HAUPPAUGE_IRONLY,
+       }, {
+               .subvendor = 0x107d,
+               .subdevice = 0x6654,
+               .card      = CX88_BOARD_WINFAST_DTV1800H,
        },
 };
 
@@ -2448,6 +2504,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
        case 90500: /* Nova-T-PCI (oem) */
        case 90501: /* Nova-T-PCI (oem/IR) */
        case 92000: /* Nova-SE2 (OEM, No Video or IR) */
+       case 92900: /* WinTV-IROnly (No analog or digital Video inputs) */
        case 94009: /* WinTV-HVR1100 (Video and IR Retail) */
        case 94501: /* WinTV-HVR1100 (Video and IR OEM) */
        case 96009: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX) */
@@ -2579,6 +2636,23 @@ static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core,
        return -EINVAL;
 }
 
+static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core,
+                                            int command, int arg)
+{
+       switch (command) {
+       case XC2028_TUNER_RESET:
+               /* GPIO 12 (xc3028 tuner reset) */
+               cx_set(MO_GP1_IO, 0x1010);
+               mdelay(50);
+               cx_clear(MO_GP1_IO, 0x10);
+               mdelay(50);
+               cx_set(MO_GP1_IO, 0x10);
+               mdelay(50);
+               return 0;
+       }
+       return -EINVAL;
+}
+
 /* ------------------------------------------------------------------- */
 /* some Divco specific stuff                                           */
 static int cx88_pv_8000gt_callback(struct cx88_core *core,
@@ -2651,6 +2725,8 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
        case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
                return cx88_dvico_xc2028_callback(core, command, arg);
+       case CX88_BOARD_WINFAST_DTV1800H:
+               return cx88_xc3028_winfast1800h_callback(core, command, arg);
        }
 
        switch (command) {
@@ -2690,10 +2766,22 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core,
        switch (core->boardnr) {
        case CX88_BOARD_PINNACLE_PCTV_HD_800i:
                if (command == 0) { /* This is the reset command from xc5000 */
-                       /* Reset XC5000 tuner via SYS_RSTO_pin */
-                       cx_write(MO_SRST_IO, 0);
-                       msleep(10);
-                       cx_write(MO_SRST_IO, 1);
+
+                       /* djh - According to the engineer at PCTV Systems,
+                          the xc5000 reset pin is supposed to be on GPIO12.
+                          However, despite three nights of effort, pulling
+                          that GPIO low didn't reset the xc5000.  While
+                          pulling MO_SRST_IO low does reset the xc5000, this
+                          also resets in the s5h1409 being reset as well.
+                          This causes tuning to always fail since the internal
+                          state of the s5h1409 does not match the driver's
+                          state.  Given that the only two conditions in which
+                          the driver performs a reset is during firmware load
+                          and powering down the chip, I am taking out the
+                          reset.  We know that the chip is being reset
+                          when the cx88 comes online, and not being able to
+                          do power management for this board is worse than
+                          not having any tuning at all. */
                        return 0;
                } else {
                        err_printk(core, "xc5000: unknown tuner "
@@ -2825,6 +2913,16 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
                cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
                udelay(1000);
                break;
+
+       case CX88_BOARD_WINFAST_DTV1800H:
+               /* GPIO 12 (xc3028 tuner reset) */
+               cx_set(MO_GP1_IO, 0x1010);
+               mdelay(50);
+               cx_clear(MO_GP1_IO, 0x10);
+               mdelay(50);
+               cx_set(MO_GP1_IO, 0x10);
+               mdelay(50);
+               break;
        }
 }
 
@@ -2845,6 +2943,7 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
                        core->i2c_algo.udelay = 16;
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+       case CX88_BOARD_WINFAST_DTV1800H:
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
        case CX88_BOARD_KWORLD_ATSC_120:
@@ -2907,6 +3006,7 @@ static void cx88_card_setup(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_HVR1300:
        case CX88_BOARD_HAUPPAUGE_HVR4000:
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+       case CX88_BOARD_HAUPPAUGE_IRONLY:
                if (0 == core->i2c_rc)
                        hauppauge_eeprom(core, eeprom);
                break;
index 0e149b22bd194b14943fa30799ec143e36270343..cf634606ba9a3bc082d0d55e77d0918452a3f16e 100644 (file)
@@ -231,7 +231,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
  * can use the whole SDRAM for the DMA fifos.  To simplify things, we
  * use a static memory layout.  That surely will waste memory in case
  * we don't use all DMA channels at the same time (which will be the
- * case most of the time).  But that still gives us enougth FIFO space
+ * case most of the time).  But that still gives us enough FIFO space
  * to be able to deal with insane long pci latencies ...
  *
  * FIFO space allocations:
@@ -241,6 +241,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
  *    channel  24    (vbi)      -  4.0k
  *    channels 25+26 (audio)    -  4.0k
  *    channel  28    (mpeg)     -  4.0k
+ *    channel  27    (audio rds)-  3.0k
  *    TOTAL                     = 29.0k
  *
  * Every channel has 160 bytes control data (64 bytes instruction
@@ -337,6 +338,18 @@ struct sram_channel cx88_sram_channels[] = {
                .cnt1_reg   = MO_DMA28_CNT1,
                .cnt2_reg   = MO_DMA28_CNT2,
        },
+       [SRAM_CH27] = {
+               .name       = "audio rds",
+               .cmds_start = 0x1801C0,
+               .ctrl_start = 0x180860,
+               .cdt        = 0x180860 + 64,
+               .fifo_start = 0x187400,
+               .fifo_size  = 0x000C00,
+               .ptr1_reg   = MO_DMA27_PTR1,
+               .ptr2_reg   = MO_DMA27_PTR2,
+               .cnt1_reg   = MO_DMA27_CNT1,
+               .cnt2_reg   = MO_DMA27_CNT2,
+       },
 };
 
 int cx88_sram_channel_setup(struct cx88_core *core,
@@ -598,6 +611,7 @@ int cx88_reset(struct cx88_core *core)
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0);
 
        /* misc init ... */
        cx_write(MO_INPUT_FORMAT, ((1 << 13) |   // agc enable
@@ -796,6 +810,8 @@ int cx88_start_audio_dma(struct cx88_core *core)
        /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
        int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
 
+       int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES;
+
        /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
        if (cx_read(MO_AUD_DMACNTRL) & 0x10)
                return 0;
@@ -803,12 +819,14 @@ int cx88_start_audio_dma(struct cx88_core *core)
        /* setup fifo + format */
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27],
+                               rds_bpl, 0);
 
        cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
-       cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */
+       cx_write(MO_AUDR_LNGTH, rds_bpl); /* fifo bpl size */
 
-       /* start dma */
-       cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
+       /* enable Up, Down and Audio RDS fifo */
+       cx_write(MO_AUD_DMACNTRL, 0x0007);
 
        return 0;
 }
@@ -1010,7 +1028,6 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       vfd->minor   = -1;
        vfd->v4l2_dev = &core->v4l2_dev;
        vfd->parent = &pci->dev;
        vfd->release = video_device_release;
diff --git a/drivers/media/video/cx88/cx88-dsp.c b/drivers/media/video/cx88/cx88-dsp.c
new file mode 100644 (file)
index 0000000..3e5eaf3
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ *
+ *  Stereo and SAP detection for cx88
+ *
+ *  Copyright (c) 2009 Marton Balint <cus@fazekas.hu>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <asm/div64.h>
+
+#include "cx88.h"
+#include "cx88-reg.h"
+
+#define INT_PI                 ((s32)(3.141592653589 * 32768.0))
+
+#define compat_remainder(a, b) \
+        ((float)(((s32)((a)*100))%((s32)((b)*100)))/100.0)
+
+#define baseband_freq(carrier, srate, tone) ((s32)( \
+        (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI))
+
+/* We calculate the baseband frequencies of the carrier and the pilot tones
+ * based on the the sampling rate of the audio rds fifo. */
+
+#define FREQ_A2_CARRIER         baseband_freq(54687.5, 2689.36, 0.0)
+#define FREQ_A2_DUAL            baseband_freq(54687.5, 2689.36, 274.1)
+#define FREQ_A2_STEREO          baseband_freq(54687.5, 2689.36, 117.5)
+
+/* The frequencies below are from the reference driver. They probably need
+ * further adjustments, because they are not tested at all. You may even need
+ * to play a bit with the registers of the chip to select the proper signal
+ * for the input of the audio rds fifo, and measure it's sampling rate to
+ * calculate the proper baseband frequencies... */
+
+#define FREQ_A2M_CARRIER       ((s32)(2.114516 * 32768.0))
+#define FREQ_A2M_DUAL          ((s32)(2.754916 * 32768.0))
+#define FREQ_A2M_STEREO                ((s32)(2.462326 * 32768.0))
+
+#define FREQ_EIAJ_CARRIER      ((s32)(1.963495 * 32768.0)) /* 5pi/8  */
+#define FREQ_EIAJ_DUAL         ((s32)(2.562118 * 32768.0))
+#define FREQ_EIAJ_STEREO       ((s32)(2.601053 * 32768.0))
+
+#define FREQ_BTSC_DUAL         ((s32)(1.963495 * 32768.0)) /* 5pi/8  */
+#define FREQ_BTSC_DUAL_REF     ((s32)(1.374446 * 32768.0)) /* 7pi/16 */
+
+#define FREQ_BTSC_SAP          ((s32)(2.471532 * 32768.0))
+#define FREQ_BTSC_SAP_REF      ((s32)(1.730072 * 32768.0))
+
+/* The spectrum of the signal should be empty between these frequencies. */
+#define FREQ_NOISE_START       ((s32)(0.100000 * 32768.0))
+#define FREQ_NOISE_END         ((s32)(1.200000 * 32768.0))
+
+static unsigned int dsp_debug;
+module_param(dsp_debug, int, 0644);
+MODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages");
+
+#define dprintk(level, fmt, arg...)    if (dsp_debug >= level) \
+       printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
+
+static s32 int_cos(u32 x)
+{
+       u32 t2, t4, t6, t8;
+       s32 ret;
+       u16 period = x / INT_PI;
+       if (period % 2)
+               return -int_cos(x - INT_PI);
+       x = x % INT_PI;
+       if (x > INT_PI/2)
+               return -int_cos(INT_PI/2 - (x % (INT_PI/2)));
+       /* Now x is between 0 and INT_PI/2.
+        * To calculate cos(x) we use it's Taylor polinom. */
+       t2 = x*x/32768/2;
+       t4 = t2*x/32768*x/32768/3/4;
+       t6 = t4*x/32768*x/32768/5/6;
+       t8 = t6*x/32768*x/32768/7/8;
+       ret = 32768-t2+t4-t6+t8;
+       return ret;
+}
+
+static u32 int_goertzel(s16 x[], u32 N, u32 freq)
+{
+       /* We use the Goertzel algorithm to determine the power of the
+        * given frequency in the signal */
+       s32 s_prev = 0;
+       s32 s_prev2 = 0;
+       s32 coeff = 2*int_cos(freq);
+       u32 i;
+
+       u64 tmp;
+       u32 divisor;
+
+       for (i = 0; i < N; i++) {
+               s32 s = x[i] + ((s64)coeff*s_prev/32768) - s_prev2;
+               s_prev2 = s_prev;
+               s_prev = s;
+       }
+
+       tmp = (s64)s_prev2 * s_prev2 + (s64)s_prev * s_prev -
+                     (s64)coeff * s_prev2 * s_prev / 32768;
+
+       /* XXX: N must be low enough so that N*N fits in s32.
+        * Else we need two divisions. */
+       divisor = N * N;
+       do_div(tmp, divisor);
+
+       return (u32) tmp;
+}
+
+static u32 freq_magnitude(s16 x[], u32 N, u32 freq)
+{
+       u32 sum = int_goertzel(x, N, freq);
+       return (u32)int_sqrt(sum);
+}
+
+static u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end)
+{
+       int i;
+       u32 sum = 0;
+       u32 freq_step;
+       int samples = 5;
+
+       if (N > 192) {
+               /* The last 192 samples are enough for noise detection */
+               x += (N-192);
+               N = 192;
+       }
+
+       freq_step = (freq_end - freq_start) / (samples - 1);
+
+       for (i = 0; i < samples; i++) {
+               sum += int_goertzel(x, N, freq_start);
+               freq_start += freq_step;
+       }
+
+       return (u32)int_sqrt(sum / samples);
+}
+
+static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N)
+{
+       s32 carrier, stereo, dual, noise;
+       s32 carrier_freq, stereo_freq, dual_freq;
+       s32 ret;
+
+       switch (core->tvaudio) {
+       case WW_BG:
+       case WW_DK:
+               carrier_freq = FREQ_A2_CARRIER;
+               stereo_freq = FREQ_A2_STEREO;
+               dual_freq = FREQ_A2_DUAL;
+               break;
+       case WW_M:
+               carrier_freq = FREQ_A2M_CARRIER;
+               stereo_freq = FREQ_A2M_STEREO;
+               dual_freq = FREQ_A2M_DUAL;
+               break;
+       case WW_EIAJ:
+               carrier_freq = FREQ_EIAJ_CARRIER;
+               stereo_freq = FREQ_EIAJ_STEREO;
+               dual_freq = FREQ_EIAJ_DUAL;
+               break;
+       default:
+               printk(KERN_WARNING "%s/0: unsupported audio mode %d for %s\n",
+                      core->name, core->tvaudio, __func__);
+               return UNSET;
+       }
+
+       carrier = freq_magnitude(x, N, carrier_freq);
+       stereo  = freq_magnitude(x, N, stereo_freq);
+       dual    = freq_magnitude(x, N, dual_freq);
+       noise   = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END);
+
+       dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, "
+                  "noise=%d\n", carrier, stereo, dual, noise);
+
+       if (stereo > dual)
+               ret = V4L2_TUNER_SUB_STEREO;
+       else
+               ret = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+       if (core->tvaudio == WW_EIAJ) {
+               /* EIAJ checks may need adjustments */
+               if ((carrier > max(stereo, dual)*2) &&
+                   (carrier < max(stereo, dual)*6) &&
+                   (carrier > 20 && carrier < 200) &&
+                   (max(stereo, dual) > min(stereo, dual))) {
+                       /* For EIAJ the carrier is always present,
+                          so we probably don't need noise detection */
+                       return ret;
+               }
+       } else {
+               if ((carrier > max(stereo, dual)*2) &&
+                   (carrier < max(stereo, dual)*8) &&
+                   (carrier > 20 && carrier < 200) &&
+                   (noise < 10) &&
+                   (max(stereo, dual) > min(stereo, dual)*2)) {
+                       return ret;
+               }
+       }
+       return V4L2_TUNER_SUB_MONO;
+}
+
+static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N)
+{
+       s32 sap_ref = freq_magnitude(x, N, FREQ_BTSC_SAP_REF);
+       s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP);
+       s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF);
+       s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL);
+       dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d"
+                  "\n", dual_ref, dual, sap_ref, sap);
+       /* FIXME: Currently not supported */
+       return UNSET;
+}
+
+static s16 *read_rds_samples(struct cx88_core *core, u32 *N)
+{
+       struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27];
+       s16 *samples;
+
+       unsigned int i;
+       unsigned int bpl = srch->fifo_size/AUD_RDS_LINES;
+       unsigned int spl = bpl/4;
+       unsigned int sample_count = spl*(AUD_RDS_LINES-1);
+
+       u32 current_address = cx_read(srch->ptr1_reg);
+       u32 offset = (current_address - srch->fifo_start + bpl);
+
+       dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), "
+               "sample_count=%d, aud_intstat=%08x\n", current_address,
+               current_address - srch->fifo_start, sample_count,
+               cx_read(MO_AUD_INTSTAT));
+
+       samples = kmalloc(sizeof(s16)*sample_count, GFP_KERNEL);
+       if (!samples)
+               return NULL;
+
+       *N = sample_count;
+
+       for (i = 0; i < sample_count; i++)  {
+               offset = offset % (AUD_RDS_LINES*bpl);
+               samples[i] = cx_read(srch->fifo_start + offset);
+               offset += 4;
+       }
+
+       if (dsp_debug >= 2) {
+               dprintk(2, "RDS samples dump: ");
+               for (i = 0; i < sample_count; i++)
+                       printk("%hd ", samples[i]);
+               printk(".\n");
+       }
+
+       return samples;
+}
+
+s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core)
+{
+       s16 *samples;
+       u32 N = 0;
+       s32 ret = UNSET;
+
+       /* If audio RDS fifo is disabled, we can't read the samples */
+       if (!(cx_read(MO_AUD_DMACNTRL) & 0x04))
+               return ret;
+       if (!(cx_read(AUD_CTL) & EN_FMRADIO_EN_RDS))
+               return ret;
+
+       /* Wait at least 500 ms after an audio standard change */
+       if (time_before(jiffies, core->last_change + msecs_to_jiffies(500)))
+               return ret;
+
+       samples = read_rds_samples(core, &N);
+
+       if (!samples)
+               return ret;
+
+       switch (core->tvaudio) {
+       case WW_BG:
+       case WW_DK:
+               ret = detect_a2_a2m_eiaj(core, samples, N);
+               break;
+       case WW_BTSC:
+               ret = detect_btsc(core, samples, N);
+               break;
+       }
+
+       kfree(samples);
+
+       if (UNSET != ret)
+               dprintk(1, "stereo/sap detection result:%s%s%s\n",
+                          (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "",
+                          (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "",
+                          (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : "");
+
+       return ret;
+}
+EXPORT_SYMBOL(cx88_dsp_detect_stereo_sap);
+
index 9389cf290c1bfc815b5752697eaf120babecbcd3..c44e8760021932bf907ce3be5e135db9f661c5a8 100644 (file)
@@ -1014,6 +1014,7 @@ static int dvb_register(struct cx8802_dev *dev)
                }
                break;
         case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+       case CX88_BOARD_WINFAST_DTV1800H:
                fe0->dvb.frontend = dvb_attach(zl10353_attach,
                                               &cx88_pinnacle_hybrid_pctv,
                                               &core->i2c_adap);
index 996b4ed5a4fc8ae414cd18abc1a6d1cdb44ef092..ee1ca39db06ad684758dc4da0bfa8b35aa8e1f56 100644 (file)
@@ -180,6 +180,19 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
                        do_i2c_scan(core->name,&core->i2c_client);
        } else
                printk("%s: i2c register FAILED\n", core->name);
+
+       /* Instantiate the IR receiver device, if present */
+       if (0 == core->i2c_rc) {
+               struct i2c_board_info info;
+               const unsigned short addr_list[] = {
+                       0x18, 0x6b, 0x71,
+                       I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&core->i2c_adap, &info, addr_list);
+       }
        return core->i2c_rc;
 }
 
index ec05312a9b6222f2ba627fde070777d17ef82188..d91f5c51206d0cdcacdae124b96ad5eca50de199 100644 (file)
@@ -91,6 +91,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
                gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
                break;
        case CX88_BOARD_WINFAST_DTV1000:
+       case CX88_BOARD_WINFAST_DTV1800H:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
                gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
                auxgpio = gpio;
                break;
@@ -217,11 +219,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
        case CX88_BOARD_PCHDTV_HD3000:
        case CX88_BOARD_PCHDTV_HD5500:
+       case CX88_BOARD_HAUPPAUGE_IRONLY:
                ir_codes = ir_codes_hauppauge_new;
                ir_type = IR_TYPE_RC5;
                ir->sampling = 1;
                break;
        case CX88_BOARD_WINFAST_DTV2000H:
+       case CX88_BOARD_WINFAST_DTV1800H:
                ir_codes = ir_codes_winfast;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
@@ -230,6 +234,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                break;
        case CX88_BOARD_WINFAST2000XP_EXPERT:
        case CX88_BOARD_WINFAST_DTV1000:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
                ir_codes = ir_codes_winfast;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
@@ -459,6 +464,7 @@ void cx88_ir_irq(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
        case CX88_BOARD_PCHDTV_HD3000:
        case CX88_BOARD_PCHDTV_HD5500:
+       case CX88_BOARD_HAUPPAUGE_IRONLY:
                ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
                ir_dprintk("biphase decoded: %x\n", ircode);
                /*
index 7dd506b987fe76d06be6788104f67ce88cd72bc2..e8316cf7f32f70b8e76b78eac4569b205cddf15d 100644 (file)
@@ -163,6 +163,8 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
        /* unmute */
        volume = cx_sread(SHADOW_AUD_VOL_CTL);
        cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume);
+
+       core->last_change = jiffies;
 }
 
 /* ----------------------------------------------------------- */
@@ -745,6 +747,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
                break;
        case WW_BG:
        case WW_DK:
+       case WW_M:
        case WW_I:
        case WW_L:
                /* prepare all dsp registers */
@@ -756,6 +759,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
                if (0 == cx88_detect_nicam(core)) {
                        /* fall back to fm / am mono */
                        set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+                       core->audiomode_current = V4L2_TUNER_MODE_MONO;
                        core->use_nicam = 0;
                } else {
                        core->use_nicam = 1;
@@ -787,6 +791,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
 void cx88_newstation(struct cx88_core *core)
 {
        core->audiomode_manual = UNSET;
+       core->last_change = jiffies;
 }
 
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
@@ -805,12 +810,50 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
                        aud_ctl_names[cx_read(AUD_CTL) & 63]);
        core->astat = reg;
 
-/* TODO
-       Reading from AUD_STATUS is not enough
-       for auto-detecting sap/dual-fm/nicam.
-       Add some code here later.
-*/
+       t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
+           V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+       t->rxsubchans = UNSET;
+       t->audmode = V4L2_TUNER_MODE_MONO;
+
+       switch (mode) {
+       case 0:
+               t->audmode = V4L2_TUNER_MODE_STEREO;
+               break;
+       case 1:
+               t->audmode = V4L2_TUNER_MODE_LANG2;
+               break;
+       case 2:
+               t->audmode = V4L2_TUNER_MODE_MONO;
+               break;
+       case 3:
+               t->audmode = V4L2_TUNER_MODE_SAP;
+               break;
+       }
 
+       switch (core->tvaudio) {
+       case WW_BTSC:
+       case WW_BG:
+       case WW_DK:
+       case WW_M:
+       case WW_EIAJ:
+               if (!core->use_nicam) {
+                       t->rxsubchans = cx88_dsp_detect_stereo_sap(core);
+                       break;
+               }
+               break;
+       default:
+               /* nothing */
+               break;
+       }
+
+       /* If software stereo detection is not supported... */
+       if (UNSET == t->rxsubchans) {
+               t->rxsubchans = V4L2_TUNER_SUB_MONO;
+               /* If the hardware itself detected stereo, also return
+                  stereo as an available subchannel */
+               if (V4L2_TUNER_MODE_STEREO == t->audmode)
+                       t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+       }
        return;
 }
 
@@ -847,6 +890,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                break;
        case WW_BG:
        case WW_DK:
+       case WW_M:
        case WW_I:
        case WW_L:
                if (1 == core->use_nicam) {
@@ -872,20 +916,18 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                                set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
                        } else {
                                /* TODO: Add A2 autodection */
+                               mask = 0x3f;
                                switch (mode) {
                                case V4L2_TUNER_MODE_MONO:
                                case V4L2_TUNER_MODE_LANG1:
-                                       set_audio_standard_A2(core,
-                                                             EN_A2_FORCE_MONO1);
+                                       ctl = EN_A2_FORCE_MONO1;
                                        break;
                                case V4L2_TUNER_MODE_LANG2:
-                                       set_audio_standard_A2(core,
-                                                             EN_A2_FORCE_MONO2);
+                                       ctl = EN_A2_FORCE_MONO2;
                                        break;
                                case V4L2_TUNER_MODE_STEREO:
                                case V4L2_TUNER_MODE_LANG1_LANG2:
-                                       set_audio_standard_A2(core,
-                                                             EN_A2_FORCE_STEREO);
+                                       ctl = EN_A2_FORCE_STEREO;
                                        break;
                                }
                        }
@@ -932,24 +974,39 @@ int cx88_audio_thread(void *data)
                        break;
                try_to_freeze();
 
-               /* just monitor the audio status for now ... */
-               memset(&t, 0, sizeof(t));
-               cx88_get_stereo(core, &t);
-
-               if (UNSET != core->audiomode_manual)
-                       /* manually set, don't do anything. */
-                       continue;
-
-               /* monitor signal */
-               if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
-                       mode = V4L2_TUNER_MODE_STEREO;
-               else
-                       mode = V4L2_TUNER_MODE_MONO;
-               if (mode == core->audiomode_current)
-                       continue;
-
-               /* automatically switch to best available mode */
-               cx88_set_stereo(core, mode, 0);
+               switch (core->tvaudio) {
+               case WW_BG:
+               case WW_DK:
+               case WW_M:
+               case WW_I:
+               case WW_L:
+                       if (core->use_nicam)
+                               goto hw_autodetect;
+
+                       /* just monitor the audio status for now ... */
+                       memset(&t, 0, sizeof(t));
+                       cx88_get_stereo(core, &t);
+
+                       if (UNSET != core->audiomode_manual)
+                               /* manually set, don't do anything. */
+                               continue;
+
+                       /* monitor signal and set stereo if available */
+                       if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
+                               mode = V4L2_TUNER_MODE_STEREO;
+                       else
+                               mode = V4L2_TUNER_MODE_MONO;
+                       if (mode == core->audiomode_current)
+                               continue;
+                       /* automatically switch to best available mode */
+                       cx88_set_stereo(core, mode, 0);
+                       break;
+               default:
+hw_autodetect:
+                       /* stereo autodetection is supported by hardware so
+                          we don't need to do it manually. Do nothing. */
+                       break;
+               }
        }
 
        dprintk("cx88: tvaudio thread exiting\n");
index b993d42fe73c138f5bfc9c289d16d1aa0a13ce13..0ccac702bea4998e66dc30dfcac3aca9282390eb 100644 (file)
@@ -869,6 +869,7 @@ video_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct cx8800_fh *fh = file->private_data;
        struct cx88_buffer *buf;
+       unsigned int rc = POLLERR;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
                if (!res_get(fh->dev,fh,RESOURCE_VBI))
@@ -876,22 +877,27 @@ video_poll(struct file *file, struct poll_table_struct *wait)
                return videobuf_poll_stream(file, &fh->vbiq, wait);
        }
 
+       mutex_lock(&fh->vidq.vb_lock);
        if (res_check(fh,RESOURCE_VIDEO)) {
                /* streaming capture */
                if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
+                       goto done;
                buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream);
        } else {
                /* read() capture */
                buf = (struct cx88_buffer*)fh->vidq.read_buf;
                if (NULL == buf)
-                       return POLLERR;
+                       goto done;
        }
        poll_wait(file, &buf->vb.done, wait);
        if (buf->vb.state == VIDEOBUF_DONE ||
            buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
+               rc = POLLIN|POLLRDNORM;
+       else
+               rc = 0;
+done:
+       mutex_unlock(&fh->vidq.vb_lock);
+       return rc;
 }
 
 static int video_release(struct file *file)
@@ -926,8 +932,10 @@ static int video_release(struct file *file)
        file->private_data = NULL;
        kfree(fh);
 
+       mutex_lock(&dev->core->lock);
        if(atomic_dec_and_test(&dev->core->users))
                call_all(dev->core, tuner, s_standby);
+       mutex_unlock(&dev->core->lock);
 
        return 0;
 }
index 7724d168fc040434d6429e01c11ca82ddaeb87ea..9d83762163f5fe8f2c0b307dc1e0bd99fcadcc14 100644 (file)
@@ -65,6 +65,8 @@
 #define VBI_LINE_COUNT              17
 #define VBI_LINE_LENGTH           2048
 
+#define AUD_RDS_LINES               4
+
 /* need "shadow" registers for some write-only ones ... */
 #define SHADOW_AUD_VOL_CTL           1
 #define SHADOW_AUD_BAL_CTL           2
@@ -132,6 +134,7 @@ struct cx88_ctrl {
 #define SRAM_CH25 4   /* audio */
 #define SRAM_CH26 5
 #define SRAM_CH28 6   /* mpeg */
+#define SRAM_CH27 7   /* audio rds */
 /* more */
 
 struct sram_channel {
@@ -232,6 +235,8 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_TBS_8910                77
 #define CX88_BOARD_PROF_6200               78
 #define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
+#define CX88_BOARD_HAUPPAUGE_IRONLY        80
+#define CX88_BOARD_WINFAST_DTV1800H        81
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -350,6 +355,7 @@ struct cx88_core {
        u32                        input;
        u32                        astat;
        u32                        use_nicam;
+       unsigned long              last_change;
 
        /* IR remote control state */
        struct cx88_IR             *ir;
@@ -652,6 +658,7 @@ extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
 #define WW_I2SPT        8
 #define WW_FM           9
 #define WW_I2SADC       10
+#define WW_M            11
 
 void cx88_set_tvaudio(struct cx88_core *core);
 void cx88_newstation(struct cx88_core *core);
@@ -664,6 +671,11 @@ int cx8802_unregister_driver(struct cx8802_driver *drv);
 struct cx8802_dev *cx8802_get_device(int minor);
 struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
 
+/* ----------------------------------------------------------- */
+/* cx88-dsp.c                                                  */
+
+s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core);
+
 /* ----------------------------------------------------------- */
 /* cx88-input.c                                                */
 
index 0131322475bfa4792619ac0b0cdb881a36035843..7bd8a70f0a0b2b5b28bdd03bd06f28a6331ac93f 100644 (file)
@@ -339,6 +339,11 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
        mutex_lock(&dev->lock);
        dev->adev.users--;
        em28xx_audio_analog_set(dev);
+       if (substream->runtime->dma_area) {
+               dprintk("freeing\n");
+               vfree(substream->runtime->dma_area);
+               substream->runtime->dma_area = NULL;
+       }
        mutex_unlock(&dev->lock);
 
        return 0;
index 7c70738479dd0ea79a1d277567ac89368655cddd..00cc791a9e440a7524aefa017d872e5a1d08894b 100644 (file)
@@ -49,6 +49,11 @@ static unsigned int disable_ir;
 module_param(disable_ir, int, 0444);
 MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
 
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+                "override min bandwidth requirement of 480M bps");
+
 static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card,     "card type");
@@ -104,6 +109,24 @@ static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
 /* Board  - EM2870 Kworld 355u
    Analog - No input analog */
 
+/* Board - EM2882 Kworld 315U digital */
+static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
+       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
+       {EM28XX_R08_GPIO,       0xfe,   0xff,           10},
+       {EM2880_R04_GPO,        0x04,   0xff,           10},
+       {EM2880_R04_GPO,        0x0c,   0xff,           10},
+       {EM28XX_R08_GPIO,       0x7e,   0xff,           10},
+       {  -1,                  -1,     -1,             -1},
+};
+
+static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
+       {EM2880_R04_GPO,        0x08,   0xff,           10},
+       {EM2880_R04_GPO,        0x0c,   0xff,           10},
+       {EM2880_R04_GPO,        0x08,   0xff,           10},
+       {EM2880_R04_GPO,        0x0c,   0xff,           10},
+       {  -1,                  -1,     -1,             -1},
+};
+
 static struct em28xx_reg_seq kworld_330u_analog[] = {
        {EM28XX_R08_GPIO,       0x6d,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x00,   0xff,           10},
@@ -140,6 +163,16 @@ static struct em28xx_reg_seq compro_mute_gpio[] = {
        {  -1,                  -1,             -1,             -1},
 };
 
+/* Terratec AV350 */
+static struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
+       {EM28XX_R08_GPIO,       0xff,   0x7f,           10},
+       {       -1,             -1,     -1,             -1},
+};
+
+static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
+       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
+       {       -1,             -1,     -1,             -1},
+};
 /*
  *  Board definitions
  */
@@ -992,16 +1025,17 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
-       [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = {
-               .name                = "PointNix Intra-Oral Camera",
+       [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = {
+               .name                = "EM2860/SAA711X Reference Design",
                .has_snapshot_button = 1,
-               .tda9887_conf        = TDA9887_PRESENT,
                .tuner_type          = TUNER_ABSENT,
                .decoder             = EM28XX_SAA711X,
                .input               = { {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = EM28XX_AMUX_VIDEO,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
                } },
        },
        [EM2880_BOARD_MSI_DIGIVOX_AD] = {
@@ -1095,6 +1129,63 @@ struct em28xx_board em28xx_boards[] = {
                        .gpio     = default_analog,
                } },
        },
+       [EM2882_BOARD_KWORLD_ATSC_315U] = {
+               .name           = "KWorld ATSC 315U HDTV TV Box",
+               .valid          = EM28XX_BOARD_NOT_VALIDATED,
+               .tuner_type     = TUNER_THOMSON_DTT761X,
+               .tuner_gpio     = em2882_kworld_315u_tuner_gpio,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .decoder        = EM28XX_SAA711X,
+               .has_dvb        = 1,
+               .dvb_gpio       = em2882_kworld_315u_digital,
+               .xclk           = EM28XX_XCLK_FREQUENCY_12MHZ,
+               .i2c_speed      = EM28XX_I2C_CLK_WAIT_ENABLE,
+               /* Analog mode - still not ready */
+               /*.input        = { {
+                       .type = EM28XX_VMUX_TELEVISION,
+                       .vmux = SAA7115_COMPOSITE2,
+                       .amux = EM28XX_AMUX_VIDEO,
+                       .gpio = em2882_kworld_315u_analog,
+                       .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+               }, {
+                       .type = EM28XX_VMUX_COMPOSITE1,
+                       .vmux = SAA7115_COMPOSITE0,
+                       .amux = EM28XX_AMUX_LINE_IN,
+                       .gpio = em2882_kworld_315u_analog1,
+                       .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+               }, {
+                       .type = EM28XX_VMUX_SVIDEO,
+                       .vmux = SAA7115_SVIDEO3,
+                       .amux = EM28XX_AMUX_LINE_IN,
+                       .gpio = em2882_kworld_315u_analog1,
+                       .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+               } }, */
+       },
+       [EM2880_BOARD_EMPIRE_DUAL_TV] = {
+               .name = "Empire dual TV",
+               .tuner_type = TUNER_XC2028,
+               .tuner_gpio = default_tuner_gpio,
+               .has_dvb = 1,
+               .dvb_gpio = default_digital,
+               .mts_firmware = 1,
+               .decoder = EM28XX_TVP5150,
+               .input = { {
+                       .type = EM28XX_VMUX_TELEVISION,
+                       .vmux = TVP5150_COMPOSITE0,
+                       .amux = EM28XX_AMUX_VIDEO,
+                       .gpio = default_analog,
+               }, {
+                       .type = EM28XX_VMUX_COMPOSITE1,
+                       .vmux = TVP5150_COMPOSITE1,
+                       .amux = EM28XX_AMUX_LINE_IN,
+                       .gpio = default_analog,
+               }, {
+                       .type = EM28XX_VMUX_SVIDEO,
+                       .vmux = TVP5150_SVIDEO,
+                       .amux = EM28XX_AMUX_LINE_IN,
+                       .gpio = default_analog,
+               } },
+       },
        [EM2881_BOARD_DNT_DA2_HYBRID] = {
                .name         = "DNT DA2 Hybrid",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
@@ -1322,6 +1413,42 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
+       [EM2860_BOARD_TERRATEC_GRABBY] = {
+               .name            = "Terratec Grabby",
+               .vchannels       = 2,
+               .tuner_type      = TUNER_ABSENT,
+               .decoder         = EM28XX_SAA711X,
+               .xclk            = EM28XX_XCLK_FREQUENCY_12MHZ,
+               .input           = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_VIDEO2,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,
+                       .amux     = EM28XX_AMUX_VIDEO2,
+               } },
+       },
+       [EM2860_BOARD_TERRATEC_AV350] = {
+               .name            = "Terratec AV350",
+               .vchannels       = 2,
+               .tuner_type      = TUNER_ABSENT,
+               .decoder         = EM28XX_TVP5150,
+               .xclk            = EM28XX_XCLK_FREQUENCY_12MHZ,
+               .mute_gpio       = terratec_av350_mute_gpio,
+               .input           = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = TVP5150_COMPOSITE1,
+                       .amux     = EM28XX_AUDIO_SRC_LINE,
+                       .gpio     = terratec_av350_unmute_gpio,
+
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = TVP5150_SVIDEO,
+                       .amux     = EM28XX_AUDIO_SRC_LINE,
+                       .gpio     = terratec_av350_unmute_gpio,
+               } },
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -1355,6 +1482,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2880_BOARD_KWORLD_DVB_305U },
        { USB_DEVICE(0xeb1a, 0xe310),
                        .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD },
+       { USB_DEVICE(0xeb1a, 0xa313),
+               .driver_info = EM2882_BOARD_KWORLD_ATSC_315U },
        { USB_DEVICE(0xeb1a, 0xa316),
                        .driver_info = EM2883_BOARD_KWORLD_HYBRID_330U },
        { USB_DEVICE(0xeb1a, 0xe320),
@@ -1385,6 +1514,10 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2870_BOARD_TERRATEC_XS },
        { USB_DEVICE(0x0ccd, 0x0047),
                        .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
+       { USB_DEVICE(0x0ccd, 0x0084),
+                       .driver_info = EM2860_BOARD_TERRATEC_AV350 },
+       { USB_DEVICE(0x0ccd, 0x0096),
+                       .driver_info = EM2860_BOARD_TERRATEC_GRABBY },
        { USB_DEVICE(0x185b, 0x2870),
                        .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE },
        { USB_DEVICE(0x185b, 0x2041),
@@ -1437,13 +1570,14 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
        {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
        {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
        {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
+       {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
 };
 
 /* I2C devicelist hash table for devices with generic USB IDs */
 static struct em28xx_hash_table em28xx_i2c_hash[] = {
        {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
        {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
-       {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT},
+       {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
        {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
 };
 
@@ -1619,6 +1753,17 @@ void em28xx_pre_card_setup(struct em28xx *dev)
                em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
                break;
 
+       case EM2882_BOARD_KWORLD_ATSC_315U:
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+               msleep(10);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+               msleep(10);
+               em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
+               msleep(10);
+               em28xx_write_reg(dev, EM2880_R04_GPO, 0x08);
+               msleep(10);
+               break;
+
        case EM2860_BOARD_KAIOMY_TVNPC_U2:
                em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1);
                em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
@@ -1664,6 +1809,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
        ctl->mts = em28xx_boards[dev->model].mts_firmware;
 
        switch (dev->model) {
+       case EM2880_BOARD_EMPIRE_DUAL_TV:
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
@@ -1835,12 +1981,20 @@ static int em28xx_hint_board(struct em28xx *dev)
 }
 
 /* ----------------------------------------------------------------------- */
-void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
+void em28xx_register_i2c_ir(struct em28xx *dev)
 {
-       if (disable_ir) {
-               ir->get_key = NULL;
-               return ;
-       }
+       struct i2c_board_info info;
+       struct IR_i2c_init_data init_data;
+       const unsigned short addr_list[] = {
+                0x30, 0x47, I2C_CLIENT_END
+       };
+
+       if (disable_ir)
+               return;
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
 
        /* detect & configure */
        switch (dev->model) {
@@ -1850,22 +2004,19 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
                break;
        case (EM2800_BOARD_TERRATEC_CINERGY_200):
        case (EM2820_BOARD_TERRATEC_CINERGY_250):
-               ir->ir_codes = ir_codes_em_terratec;
-               ir->get_key = em28xx_get_key_terratec;
-               snprintf(ir->c.name, sizeof(ir->c.name),
-                        "i2c IR (EM28XX Terratec)");
+               init_data.ir_codes = ir_codes_em_terratec;
+               init_data.get_key = em28xx_get_key_terratec;
+               init_data.name = "i2c IR (EM28XX Terratec)";
                break;
        case (EM2820_BOARD_PINNACLE_USB_2):
-               ir->ir_codes = ir_codes_pinnacle_grey;
-               ir->get_key = em28xx_get_key_pinnacle_usb_grey;
-               snprintf(ir->c.name, sizeof(ir->c.name),
-                        "i2c IR (EM28XX Pinnacle PCTV)");
+               init_data.ir_codes = ir_codes_pinnacle_grey;
+               init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
+               init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
                break;
        case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
-               ir->ir_codes = ir_codes_hauppauge_new;
-               ir->get_key = em28xx_get_key_em_haup;
-               snprintf(ir->c.name, sizeof(ir->c.name),
-                        "i2c IR (EM2840 Hauppauge)");
+               init_data.ir_codes = ir_codes_hauppauge_new;
+               init_data.get_key = em28xx_get_key_em_haup;
+               init_data.name = "i2c IR (EM2840 Hauppauge)";
                break;
        case (EM2820_BOARD_MSI_VOX_USB_2):
                break;
@@ -1876,6 +2027,10 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
        case (EM2800_BOARD_GRABBEEX_USB2800):
                break;
        }
+
+       if (init_data.name)
+               info.platform_data = &init_data;
+       i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
 }
 
 void em28xx_card_setup(struct em28xx *dev)
@@ -1886,6 +2041,9 @@ void em28xx_card_setup(struct em28xx *dev)
        if (em28xx_boards[dev->model].tuner_addr)
                dev->tuner_addr = em28xx_boards[dev->model].tuner_addr;
 
+       if (em28xx_boards[dev->model].tda9887_conf)
+               dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+
        /* request some modules */
        switch (dev->model) {
        case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
@@ -1915,6 +2073,12 @@ void em28xx_card_setup(struct em28xx *dev)
 #endif
                break;
        }
+       case EM2882_BOARD_KWORLD_ATSC_315U:
+               em28xx_write_reg(dev, 0x0d, 0x42);
+               msleep(10);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+               msleep(10);
+               break;
        case EM2820_BOARD_KWORLD_PVRTV2800RF:
                /* GPIO enables sound on KWORLD PVR TV 2800RF */
                em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9);
@@ -2279,6 +2443,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                ifnum,
                interface->altsetting->desc.bInterfaceNumber);
 
+       /*
+        * Make sure we have 480 Mbps of bandwidth, otherwise things like
+        * video stream wouldn't likely work, since 12 Mbps is generally
+        * not enough even for most Digital TV streams.
+        */
+       if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+               printk(DRIVER_NAME ": Device initialization failed.\n");
+               printk(DRIVER_NAME ": Device must be connected to a high-speed"
+                      " USB 2.0 port.\n");
+               em28xx_devused &= ~(1<<nr);
+               retval = -ENODEV;
+               goto err;
+       }
+
        if (nr >= EM28XX_MAXBOARDS) {
                printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
                                EM28XX_MAXBOARDS);
index 192b76cdd5d733fb300b73e2dee2ee9134104ff4..c8d7ce8fbd368a403c47e6260e036801182144e9 100644 (file)
@@ -500,18 +500,21 @@ int em28xx_audio_setup(struct em28xx *dev)
 
        /* See how this device is configured */
        cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
-       if (cfg < 0)
+       em28xx_info("Config register raw data: 0x%02x\n", cfg);
+       if (cfg < 0) {
+               /* Register read error?  */
                cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
-       else
-               em28xx_info("Config register raw data: 0x%02x\n", cfg);
-
-       if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
-                   EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
+       } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
+               /* The device doesn't have vendor audio at all */
+               dev->has_alsa_audio = 0;
+               dev->audio_mode.has_audio = 0;
+               return 0;
+       } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+                  EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
                em28xx_info("I2S Audio (3 sample rates)\n");
                dev->audio_mode.i2s_3rates = 1;
-       }
-       if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
-                   EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
+       } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+                  EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
                em28xx_info("I2S Audio (5 sample rates)\n");
                dev->audio_mode.i2s_5rates = 1;
        }
@@ -938,7 +941,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
        dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
                                              GFP_KERNEL);
        if (!dev->isoc_ctl.transfer_buffer) {
-               em28xx_errdev("cannot allocate memory for usbtransfer\n");
+               em28xx_errdev("cannot allocate memory for usb transfer\n");
                kfree(dev->isoc_ctl.urb);
                return -ENOMEM;
        }
@@ -1012,6 +1015,41 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
 }
 EXPORT_SYMBOL_GPL(em28xx_init_isoc);
 
+/* Determine the packet size for the DVB stream for the given device
+   (underlying value programmed into the eeprom) */
+int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
+{
+       unsigned int chip_cfg2;
+       unsigned int packet_size = 564;
+
+       if (dev->chip_id == CHIP_ID_EM2874) {
+               /* FIXME - for now assume 564 like it was before, but the
+                  em2874 code should be added to return the proper value... */
+               packet_size = 564;
+       } else {
+               /* TS max packet size stored in bits 1-0 of R01 */
+               chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
+               switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) {
+               case EM28XX_CHIPCFG2_TS_PACKETSIZE_188:
+                       packet_size = 188;
+                       break;
+               case EM28XX_CHIPCFG2_TS_PACKETSIZE_376:
+                       packet_size = 376;
+                       break;
+               case EM28XX_CHIPCFG2_TS_PACKETSIZE_564:
+                       packet_size = 564;
+                       break;
+               case EM28XX_CHIPCFG2_TS_PACKETSIZE_752:
+                       packet_size = 752;
+                       break;
+               }
+       }
+
+       em28xx_coredbg("dvb max packet size=%d\n", packet_size);
+       return packet_size;
+}
+EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize);
+
 /*
  * em28xx_wake_i2c()
  * configure i2c attached devices
index fcd25511209bc985f7273f057340a1bf07c6f5d2..563dd2b1c8e90e8d9efc0f8f4b967eb8b0fb7bdb 100644 (file)
@@ -25,6 +25,8 @@
 #include "em28xx.h"
 #include <media/v4l2-common.h>
 #include <media/videobuf-vmalloc.h>
+#include <media/tuner.h>
+#include "tuner-simple.h"
 
 #include "lgdt330x.h"
 #include "zl10353.h"
@@ -46,7 +48,6 @@ if (debug >= level)                                           \
 } while (0)
 
 #define EM28XX_DVB_NUM_BUFS 5
-#define EM28XX_DVB_MAX_PACKETSIZE 564
 #define EM28XX_DVB_MAX_PACKETS 64
 
 struct em28xx_dvb {
@@ -142,14 +143,17 @@ static int start_streaming(struct em28xx_dvb *dvb)
 {
        int rc;
        struct em28xx *dev = dvb->adapter.priv;
+       int max_dvb_packet_size;
 
        usb_set_interface(dev->udev, 0, 1);
        rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        if (rc < 0)
                return rc;
 
+       max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
+
        return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
-                               EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
+                               EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
                                dvb_isoc_copy);
 }
 
@@ -431,6 +435,7 @@ static int dvb_init(struct em28xx *dev)
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
        case EM2880_BOARD_TERRATEC_HYBRID_XS:
        case EM2880_BOARD_KWORLD_DVB_310U:
+       case EM2880_BOARD_EMPIRE_DUAL_TV:
                dvb->frontend = dvb_attach(zl10353_attach,
                                           &em28xx_zl10353_with_xc3028,
                                           &dev->i2c_adap);
@@ -448,6 +453,18 @@ static int dvb_init(struct em28xx *dev)
                        goto out_free;
                }
                break;
+       case EM2882_BOARD_KWORLD_ATSC_315U:
+               dvb->frontend = dvb_attach(lgdt330x_attach,
+                                          &em2880_lgdt3303_dev,
+                                          &dev->i2c_adap);
+               if (dvb->frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, dvb->frontend,
+                               &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
+                               result = -EINVAL;
+                               goto out_free;
+                       }
+               }
+               break;
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
 #ifdef EM28XX_DRX397XD_SUPPORT
                /* We don't have the config structure properly populated, so
index f0bf1d960c759a081652ade96e3573d6326a6113..2c86fcf089f59b45de048179e4be46fe76c989d4 100644 (file)
@@ -451,27 +451,6 @@ static u32 functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL;
 }
 
-/*
- * attach_inform()
- * gets called when a device attaches to the i2c bus
- * does some basic configuration
- */
-static int attach_inform(struct i2c_client *client)
-{
-       struct em28xx *dev = client->adapter->algo_data;
-       struct IR_i2c *ir = i2c_get_clientdata(client);
-
-       switch (client->addr << 1) {
-       case 0x60:
-       case 0x8e:
-               dprintk1(1, "attach_inform: IR detected (%s).\n", ir->phys);
-               em28xx_set_ir(dev, ir);
-               break;
-       }
-
-       return 0;
-}
-
 static struct i2c_algorithm em28xx_algo = {
        .master_xfer   = em28xx_i2c_xfer,
        .functionality = functionality,
@@ -482,7 +461,6 @@ static struct i2c_adapter em28xx_adap_template = {
        .name = "em28xx",
        .id = I2C_HW_B_EM28XX,
        .algo = &em28xx_algo,
-       .client_register = attach_inform,
 };
 
 static struct i2c_client em28xx_client_template = {
@@ -575,6 +553,9 @@ int em28xx_i2c_register(struct em28xx *dev)
        if (i2c_scan)
                em28xx_do_i2c_scan(dev);
 
+       /* Instantiate the IR receiver device, if present */
+       em28xx_register_i2c_ir(dev);
+
        return 0;
 }
 
index a5abfd7a19f577d4e00bd4bbaf42f647641b9385..7a0fe3816e3db6613d051c528ac8a25347ea8d97 100644 (file)
@@ -40,7 +40,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 
 #define i2cdprintk(fmt, arg...) \
        if (ir_debug) { \
-               printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
        }
 
 #define dprintk(fmt, arg...) \
@@ -85,7 +85,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -114,7 +114,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char code;
 
        /* poll IR chip */
-       if (2 != i2c_master_recv(&ir->c, buf, 2))
+       if (2 != i2c_master_recv(ir->c, buf, 2))
                return -EIO;
 
        /* Does eliminate repeated parity code */
@@ -147,7 +147,7 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
 
        /* poll IR chip */
 
-       if (3 != i2c_master_recv(&ir->c, buf, 3)) {
+       if (3 != i2c_master_recv(ir->c, buf, 3)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
index 24e39c56811e98713f8497cca6f46fbd48409209..a2676d63cfd0a673cfd26b6e0ddd593ecab10e5a 100644 (file)
 #define EM28XX_CHIPCFG_AC97                    0x10
 #define EM28XX_CHIPCFG_AUDIOMASK               0x30
 
+#define EM28XX_R01_CHIPCFG2    0x01
+
+/* em28xx Chip Configuration 2 0x01 */
+#define EM28XX_CHIPCFG2_TS_PRESENT             0x10
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_MASK   0x0c /* bits 3-2 */
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_1MF    0x00
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_2MF    0x04
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_4MF    0x08
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_8MF    0x0c
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK     0x03 /* bits 0-1 */
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_188      0x00
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_376      0x01
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564      0x02
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752      0x03
+
+
        /* GPIO/GPO registers */
 #define EM2880_R04_GPO 0x04    /* em2880-em2883 only */
 #define EM28XX_R08_GPIO        0x08    /* em2820 or upper */
index 4c4e58004f5473fb8c2c1d0dfb188f4d1b4a8b51..8bf81be1da615eee54c89d5961e19283dd8ef64c 100644 (file)
@@ -58,7 +58,7 @@
 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950   16
 #define EM2880_BOARD_PINNACLE_PCTV_HD_PRO      17
 #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2        18
-#define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA  19
+#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN  19
 #define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600   20
 #define EM2800_BOARD_GRABBEEX_USB2800           21
 #define EM2750_BOARD_UNKNOWN                     22
 #define EM2860_BOARD_KAIOMY_TVNPC_U2              63
 #define EM2860_BOARD_EASYCAP                      64
 #define EM2820_BOARD_IODATA_GVMVP_SZ             65
+#define EM2880_BOARD_EMPIRE_DUAL_TV              66
+#define EM2860_BOARD_TERRATEC_GRABBY             67
+#define EM2860_BOARD_TERRATEC_AV350              68
+#define EM2882_BOARD_KWORLD_ATSC_315U            69
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -615,6 +619,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
                     int num_bufs, int max_pkt_size,
                     int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
 void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
 void em28xx_wake_i2c(struct em28xx *dev);
@@ -639,7 +644,7 @@ extern void em28xx_card_setup(struct em28xx *dev);
 extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
-void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
+void em28xx_register_i2c_ir(struct em28xx *dev);
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_release_resources(struct em28xx *dev);
 
index 00e6863ed66692d20581b88559041084fed917ad..480ec5c87d0ed3ecc8696ad1cd2a56ad007a10f3 100644 (file)
@@ -168,6 +168,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam->cam_mode = fpix_mode;
        cam->nmodes = 1;
+       cam->bulk = 1;
        cam->bulk_size = FPIX_MAX_TRANSFER;
 
        INIT_WORK(&dev->work_struct, dostream);
index a2741d7dccfeca4696c0167fce5b317f5eba7e56..f7e0355ad644f5181bcdbbd36bb3fa1b9483f82e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Main USB camera driver
  *
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2008-2009 Jean-Francois Moine (http://moinejf.free.fr)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -47,7 +47,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 5, 0)
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 6, 0)
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -441,7 +441,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
  * look for an input transfer endpoint in an alternate setting
  */
 static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
-                                         __u8 xfer)
+                                         int xfer)
 {
        struct usb_host_endpoint *ep;
        int i, attr;
@@ -449,7 +449,8 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
        for (i = 0; i < alt->desc.bNumEndpoints; i++) {
                ep = &alt->endpoint[i];
                attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-               if (attr == xfer)
+               if (attr == xfer
+                   && ep->desc.wMaxPacketSize != 0)
                        return ep;
        }
        return NULL;
@@ -467,37 +468,28 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
 {
        struct usb_interface *intf;
        struct usb_host_endpoint *ep;
-       int i, ret;
+       int xfer, i, ret;
 
        intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
        ep = NULL;
+       xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
+                                  : USB_ENDPOINT_XFER_ISOC;
        i = gspca_dev->alt;                     /* previous alt setting */
-
-       /* try isoc */
        while (--i >= 0) {
-               ep = alt_xfer(&intf->altsetting[i],
-                               USB_ENDPOINT_XFER_ISOC);
+               ep = alt_xfer(&intf->altsetting[i], xfer);
                if (ep)
                        break;
        }
-
-       /* if no isoc, try bulk (alt 0 only) */
        if (ep == NULL) {
-               ep = alt_xfer(&intf->altsetting[0],
-                               USB_ENDPOINT_XFER_BULK);
-               if (ep == NULL) {
-                       err("no transfer endpoint found");
-                       return NULL;
-               }
-               i = 0;
-               gspca_dev->bulk = 1;
+               err("no transfer endpoint found");
+               return NULL;
        }
        PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
                        i, ep->desc.bEndpointAddress);
-       if (i > 0) {
+       if (gspca_dev->nbalt > 1) {
                ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
                if (ret < 0) {
-                       err("set interface err %d", ret);
+                       err("set alt %d err %d", i, ret);
                        return NULL;
                }
        }
@@ -517,13 +509,13 @@ static int create_urbs(struct gspca_dev *gspca_dev,
        /* calculate the packet size and the number of packets */
        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
 
-       if (!gspca_dev->bulk) {                 /* isoc */
+       if (!gspca_dev->cam.bulk) {             /* isoc */
 
                /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
                psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
-               npkt = ISO_MAX_SIZE / psize;
-               if (npkt > ISO_MAX_PKT)
-                       npkt = ISO_MAX_PKT;
+               npkt = gspca_dev->cam.npkt;
+               if (npkt == 0)
+                       npkt = 32;              /* default value */
                bsize = psize * npkt;
                PDEBUG(D_STREAM,
                        "isoc %d pkts size %d = bsize:%d",
@@ -617,7 +609,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                        goto out;
 
                /* clear the bulk endpoint */
-               if (gspca_dev->bulk)
+               if (gspca_dev->cam.bulk)
                        usb_clear_halt(gspca_dev->dev,
                                        gspca_dev->urb[0]->pipe);
 
@@ -630,7 +622,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                gspca_dev->streaming = 1;
 
                /* some bulk transfers are started by the subdriver */
-               if (gspca_dev->bulk && gspca_dev->cam.bulk_nurbs == 0)
+               if (gspca_dev->cam.bulk && gspca_dev->cam.bulk_nurbs == 0)
                        break;
 
                /* submit the URBs */
@@ -661,6 +653,8 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
 {
        int ret;
 
+       if (gspca_dev->alt == 0)
+               return 0;
        ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
        if (ret < 0)
                PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret);
@@ -869,6 +863,32 @@ out:
        return ret;
 }
 
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+                                 struct v4l2_frmsizeenum *fsize)
+{
+       struct gspca_dev *gspca_dev = priv;
+       int i;
+       __u32 index = 0;
+
+       for (i = 0; i < gspca_dev->cam.nmodes; i++) {
+               if (fsize->pixel_format !=
+                               gspca_dev->cam.cam_mode[i].pixelformat)
+                       continue;
+
+               if (fsize->index == index) {
+                       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+                       fsize->discrete.width =
+                               gspca_dev->cam.cam_mode[i].width;
+                       fsize->discrete.height =
+                               gspca_dev->cam.cam_mode[i].height;
+                       return 0;
+               }
+               index++;
+       }
+
+       return -EINVAL;
+}
+
 static void gspca_release(struct video_device *vfd)
 {
        struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev);
@@ -989,43 +1009,54 @@ out:
        return ret;
 }
 
+static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev,
+                                  int id)
+{
+       const struct ctrl *ctrls;
+       int i;
+
+       for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+            i < gspca_dev->sd_desc->nctrls;
+            i++, ctrls++) {
+               if (gspca_dev->ctrl_dis & (1 << i))
+                       continue;
+               if (id == ctrls->qctrl.id)
+                       return ctrls;
+       }
+       return NULL;
+}
+
 static int vidioc_queryctrl(struct file *file, void *priv,
                           struct v4l2_queryctrl *q_ctrl)
 {
        struct gspca_dev *gspca_dev = priv;
-       int i, ix;
+       const struct ctrl *ctrls;
+       int i;
        u32 id;
 
-       ix = -1;
+       ctrls = NULL;
        id = q_ctrl->id;
        if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
                id &= V4L2_CTRL_ID_MASK;
                id++;
                for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-                       if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
+                       if (gspca_dev->ctrl_dis & (1 << i))
                                continue;
-                       if (ix < 0) {
-                               ix = i;
+                       if (ctrls->qctrl.id < id)
                                continue;
+                       if (ctrls != NULL) {
+                               if (gspca_dev->sd_desc->ctrls[i].qctrl.id
+                                           > ctrls->qctrl.id)
+                                       continue;
                        }
-                       if (gspca_dev->sd_desc->ctrls[i].qctrl.id
-                                   > gspca_dev->sd_desc->ctrls[ix].qctrl.id)
-                               continue;
-                       ix = i;
-               }
-       }
-       for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-               if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
-                       ix = i;
-                       break;
+                       ctrls = &gspca_dev->sd_desc->ctrls[i];
                }
+       } else {
+               ctrls = get_ctrl(gspca_dev, id);
        }
-       if (ix < 0)
+       if (ctrls == NULL)
                return -EINVAL;
-       memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl,
-               sizeof *q_ctrl);
-       if (gspca_dev->ctrl_dis & (1 << ix))
-               q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+       memcpy(q_ctrl, ctrls, sizeof *q_ctrl);
        return 0;
 }
 
@@ -1034,56 +1065,45 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
        const struct ctrl *ctrls;
-       int i, ret;
+       int ret;
 
-       for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
-            i < gspca_dev->sd_desc->nctrls;
-            i++, ctrls++) {
-               if (ctrl->id != ctrls->qctrl.id)
-                       continue;
-               if (gspca_dev->ctrl_dis & (1 << i))
-                       return -EINVAL;
-               if (ctrl->value < ctrls->qctrl.minimum
-                   || ctrl->value > ctrls->qctrl.maximum)
-                       return -ERANGE;
-               PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
-               if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-                       return -ERESTARTSYS;
-               if (gspca_dev->present)
-                       ret = ctrls->set(gspca_dev, ctrl->value);
-               else
-                       ret = -ENODEV;
-               mutex_unlock(&gspca_dev->usb_lock);
-               return ret;
-       }
-       return -EINVAL;
+       ctrls = get_ctrl(gspca_dev, ctrl->id);
+       if (ctrls == NULL)
+               return -EINVAL;
+
+       if (ctrl->value < ctrls->qctrl.minimum
+           || ctrl->value > ctrls->qctrl.maximum)
+               return -ERANGE;
+       PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
+       if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+               return -ERESTARTSYS;
+       if (gspca_dev->present)
+               ret = ctrls->set(gspca_dev, ctrl->value);
+       else
+               ret = -ENODEV;
+       mutex_unlock(&gspca_dev->usb_lock);
+       return ret;
 }
 
 static int vidioc_g_ctrl(struct file *file, void *priv,
                         struct v4l2_control *ctrl)
 {
        struct gspca_dev *gspca_dev = priv;
-
        const struct ctrl *ctrls;
-       int i, ret;
+       int ret;
 
-       for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
-            i < gspca_dev->sd_desc->nctrls;
-            i++, ctrls++) {
-               if (ctrl->id != ctrls->qctrl.id)
-                       continue;
-               if (gspca_dev->ctrl_dis & (1 << i))
-                       return -EINVAL;
-               if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-                       return -ERESTARTSYS;
-               if (gspca_dev->present)
-                       ret = ctrls->get(gspca_dev, &ctrl->value);
-               else
-                       ret = -ENODEV;
-               mutex_unlock(&gspca_dev->usb_lock);
-               return ret;
-       }
-       return -EINVAL;
+       ctrls = get_ctrl(gspca_dev, ctrl->id);
+       if (ctrls == NULL)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+               return -ERESTARTSYS;
+       if (gspca_dev->present)
+               ret = ctrls->get(gspca_dev, &ctrl->value);
+       else
+               ret = -ENODEV;
+       mutex_unlock(&gspca_dev->usb_lock);
+       return ret;
 }
 
 /*fixme: have an audio flag in gspca_dev?*/
@@ -1864,6 +1884,7 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
        .vidioc_g_parm          = vidioc_g_parm,
        .vidioc_s_parm          = vidioc_s_parm,
        .vidioc_s_std           = vidioc_s_std,
+       .vidioc_enum_framesizes = vidioc_enum_framesizes,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf          = vidiocgmbuf,
 #endif
@@ -1943,7 +1964,7 @@ int gspca_dev_probe(struct usb_interface *intf,
 
        /* init video stuff */
        memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);
-       gspca_dev->vdev.parent = &dev->dev;
+       gspca_dev->vdev.parent = &intf->dev;
        gspca_dev->module = module;
        gspca_dev->present = 1;
        ret = video_register_device(&gspca_dev->vdev,
index 58e8ff02136a46bbca14802753c3c09e45115314..bd1faff8864454a9aa163603570fb62c935eab64 100644 (file)
@@ -44,8 +44,6 @@ extern int gspca_debug;
 #define GSPCA_MAX_FRAMES 16    /* maximum number of video frame buffers */
 /* image transfers */
 #define MAX_NURBS 4            /* max number of URBs */
-#define ISO_MAX_PKT 32         /* max number of packets in an ISOC transfer */
-#define ISO_MAX_SIZE 0x8000    /* max size of one URB buffer (32 Kb) */
 
 /* device information - set at probe time */
 struct cam {
@@ -56,6 +54,9 @@ struct cam {
                                 * - cannot be > MAX_NURBS
                                 * - when 0 and bulk_size != 0 means
                                 *   1 URB and submit done by subdriver */
+       u8 bulk;                /* image transfer by 0:isoc / 1:bulk */
+       u8 npkt;                /* number of packets in an ISOC message
+                                * 0 is the default value: 32 packets */
        u32 input_flags;        /* value for ENUM_INPUT status flags */
 };
 
@@ -168,7 +169,6 @@ struct gspca_dev {
        __u8 iface;                     /* USB interface number */
        __u8 alt;                       /* USB alternate setting */
        __u8 nbalt;                     /* number of USB alternate settings */
-       u8 bulk;                        /* image transfer by 0:isoc / 1:bulk */
 };
 
 int gspca_dev_probe(struct usb_interface *intf,
index 9fa3644f4869971d73aa76337c625da57e8f5eb3..bf7a19a1e6d1470c3b5dbc611187a499ea53add8 100644 (file)
@@ -2,9 +2,10 @@ obj-$(CONFIG_USB_M5602) += gspca_m5602.o
 
 gspca_m5602-objs := m5602_core.o \
                    m5602_ov9650.o \
+                   m5602_ov7660.o \
                    m5602_mt9m111.o \
                    m5602_po1030.o \
                    m5602_s5k83a.o \
                    m5602_s5k4aa.o
 
-EXTRA_CFLAGS += -Idrivers/media/video/gspca
\ No newline at end of file
+EXTRA_CFLAGS += -Idrivers/media/video/gspca
index 8f1cea6fd3bface9c601eda1dc6de8befc507a0b..1127a405c9b2ce2f9687aff3292ecf6fc7d31b6c 100644 (file)
 #define M5602_XB_SEN_CLK_DIV           0x15
 #define M5602_XB_AUD_CLK_CTRL          0x16
 #define M5602_XB_AUD_CLK_DIV           0x17
+#define M5602_OB_AC_LINK_STATE         0x22
+#define M5602_OB_PCM_SLOT_INDEX                0x24
+#define M5602_OB_GPIO_SLOT_INDEX       0x25
+#define M5602_OB_ACRX_STATUS_ADDRESS_H 0x28
+#define M5602_OB_ACRX_STATUS_DATA_L    0x29
+#define M5602_OB_ACRX_STATUS_DATA_H    0x2a
+#define M5602_OB_ACTX_COMMAND_ADDRESS  0x31
+#define M5602_OB_ACRX_COMMAND_DATA_L   0x32
+#define M5602_OB_ACTX_COMMAND_DATA_H   0X33
 #define M5602_XB_DEVCTR1               0x41
 #define M5602_XB_EPSETR0               0x42
 #define M5602_XB_EPAFCTR               0x47
 #define M5602_XB_GPIO_EN_L             0x75
 #define M5602_XB_GPIO_DAT              0x76
 #define M5602_XB_GPIO_DIR              0x77
-#define M5602_XB_MISC_CTL              0x70
+#define M5602_XB_SEN_CLK_CONTROL       0x80
+#define M5602_XB_SEN_CLK_DIVISION      0x81
+#define M5602_XB_CPR_CLK_CONTROL       0x82
+#define M5602_XB_CPR_CLK_DIVISION      0x83
+#define M5602_XB_MCU_CLK_CONTROL       0x84
+#define M5602_XB_MCU_CLK_DIVISION      0x85
+#define M5602_XB_DCT_CLK_CONTROL       0x86
+#define M5602_XB_DCT_CLK_DIVISION      0x87
+#define M5602_XB_EC_CLK_CONTROL                0x88
+#define M5602_XB_EC_CLK_DIVISION       0x89
+#define M5602_XB_LBUF_CLK_CONTROL      0x8a
+#define M5602_XB_LBUF_CLK_DIVISION     0x8b
 
 #define I2C_BUSY 0x80
 
@@ -128,10 +148,10 @@ struct sd {
 };
 
 int m5602_read_bridge(
-       struct sd *sd, u8 address, u8 *i2c_data);
+       struct sd *sd, const u8 address, u8 *i2c_data);
 
 int m5602_write_bridge(
-       struct sd *sd, u8 address, u8 i2c_data);
+       struct sd *sd, const u8 address, const u8 i2c_data);
 
 int m5602_write_sensor(struct sd *sd, const u8 address,
                       u8 *i2c_data, const u8 len);
index 1aac2985fee6db002240466fbabd0981ee350f43..8a5bba16ff32379c2b0472f25a33cc9e5863a257 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include "m5602_ov9650.h"
+#include "m5602_ov7660.h"
 #include "m5602_mt9m111.h"
 #include "m5602_po1030.h"
 #include "m5602_s5k83a.h"
@@ -35,7 +36,7 @@ static const __devinitdata struct usb_device_id m5602_table[] = {
 MODULE_DEVICE_TABLE(usb, m5602_table);
 
 /* Reads a byte from the m5602 */
-int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
+int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
 {
        int err;
        struct usb_device *udev = sd->gspca_dev.dev;
@@ -56,7 +57,7 @@ int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
 }
 
 /* Writes a byte to to the m5602 */
-int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
+int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data)
 {
        int err;
        struct usb_device *udev = sd->gspca_dev.dev;
@@ -80,6 +81,17 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
        return (err < 0) ? err : 0;
 }
 
+int m5602_wait_for_i2c(struct sd *sd)
+{
+       int err;
+       u8 data;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data);
+       } while ((data & I2C_BUSY) && !err);
+       return err;
+}
+
 int m5602_read_sensor(struct sd *sd, const u8 address,
                       u8 *i2c_data, const u8 len)
 {
@@ -88,9 +100,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
        if (!len || len > sd->sensor->i2c_regW)
                return -EINVAL;
 
-       do {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
-       } while ((*i2c_data & I2C_BUSY) && !err);
+       err = m5602_wait_for_i2c(sd);
        if (err < 0)
                return err;
 
@@ -103,21 +113,25 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
        if (err < 0)
                return err;
 
+       /* Sensors with registers that are of only
+          one byte width are differently read */
+
+       /* FIXME: This works with the ov9650, but has issues with the po1030 */
        if (sd->sensor->i2c_regW == 1) {
-               err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, len);
+               err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 1);
                if (err < 0)
                        return err;
 
                err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
-               if (err < 0)
-                       return err;
        } else {
                err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
-               if (err < 0)
-                       return err;
        }
 
        for (i = 0; (i < len) && !err; i++) {
+               err = m5602_wait_for_i2c(sd);
+               if (err < 0)
+                       return err;
+
                err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
 
                PDEBUG(D_CONF, "Reading sensor register "
@@ -206,6 +220,11 @@ static int m5602_probe_sensor(struct sd *sd)
        if (!sd->sensor->probe(sd))
                return 0;
 
+       /* Try the ov7660 */
+       sd->sensor = &ov7660;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
        /* Try the s5k83a */
        sd->sensor = &s5k83a;
        if (!sd->sensor->probe(sd))
@@ -409,8 +428,9 @@ MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 module_param(force_sensor, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(force_sensor,
-               "force detection of sensor, "
-               "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, 4 = MT9M111, 5 = PO1030");
+               "forces detection of a sensor, "
+               "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, "
+               "4 = MT9M111, 5 = PO1030, 6 = OV7660");
 
 module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
index 7d3f9e348ef4d5b6a576da145611da5d367e1c24..8d071dff6944bf01d178180764f70cf166e17b5b 100644 (file)
 
 #include "m5602_mt9m111.h"
 
+static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val);
+static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                         __s32 *val);
+static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+
 static struct v4l2_pix_format mt9m111_modes[] = {
        {
                640,
@@ -32,6 +49,7 @@ static struct v4l2_pix_format mt9m111_modes[] = {
 };
 
 const static struct ctrl mt9m111_ctrls[] = {
+#define VFLIP_IDX 0
        {
                {
                        .id             = V4L2_CID_VFLIP,
@@ -44,7 +62,9 @@ const static struct ctrl mt9m111_ctrls[] = {
                },
                .set = mt9m111_set_vflip,
                .get = mt9m111_get_vflip
-       }, {
+       },
+#define HFLIP_IDX 1
+       {
                {
                        .id             = V4L2_CID_HFLIP,
                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -56,7 +76,9 @@ const static struct ctrl mt9m111_ctrls[] = {
                },
                .set = mt9m111_set_hflip,
                .get = mt9m111_get_hflip
-       }, {
+       },
+#define GAIN_IDX 2
+       {
                {
                        .id             = V4L2_CID_GAIN,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -64,21 +86,80 @@ const static struct ctrl mt9m111_ctrls[] = {
                        .minimum        = 0,
                        .maximum        = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
                        .step           = 1,
-                       .default_value  = DEFAULT_GAIN,
+                       .default_value  = MT9M111_DEFAULT_GAIN,
                        .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = mt9m111_set_gain,
                .get = mt9m111_get_gain
-       }
+       },
+#define AUTO_WHITE_BALANCE_IDX 3
+       {
+               {
+                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto white balance",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
+               },
+               .set = mt9m111_set_auto_white_balance,
+               .get = mt9m111_get_auto_white_balance
+       },
+#define GREEN_BALANCE_IDX 4
+       {
+               {
+                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "green balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0x7ff,
+                       .step           = 0x1,
+                       .default_value  = MT9M111_GREEN_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = mt9m111_set_green_balance,
+               .get = mt9m111_get_green_balance
+       },
+#define BLUE_BALANCE_IDX 5
+       {
+               {
+                       .id             = V4L2_CID_BLUE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "blue balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0x7ff,
+                       .step           = 0x1,
+                       .default_value  = MT9M111_BLUE_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = mt9m111_set_blue_balance,
+               .get = mt9m111_get_blue_balance
+       },
+#define RED_BALANCE_IDX 5
+       {
+               {
+                       .id             = V4L2_CID_RED_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "red balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0x7ff,
+                       .step           = 0x1,
+                       .default_value  = MT9M111_RED_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = mt9m111_set_red_balance,
+               .get = mt9m111_get_red_balance
+       },
 };
 
-
 static void mt9m111_dump_registers(struct sd *sd);
 
 int mt9m111_probe(struct sd *sd)
 {
        u8 data[2] = {0x00, 0x00};
        int i;
+       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == MT9M111_SENSOR) {
@@ -117,16 +198,27 @@ int mt9m111_probe(struct sd *sd)
        return -ENODEV;
 
 sensor_found:
+       sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
+                                 GFP_KERNEL);
+       if (!sensor_settings)
+               return -ENOMEM;
+
        sd->gspca_dev.cam.cam_mode = mt9m111_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
        sd->desc->ctrls = mt9m111_ctrls;
        sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
+
+       for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
+               sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
+       sd->sensor_priv = sensor_settings;
+
        return 0;
 }
 
 int mt9m111_init(struct sd *sd)
 {
        int i, err = 0;
+       s32 *sensor_settings = sd->sensor_priv;
 
        /* Init the sensor */
        for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
@@ -147,36 +239,154 @@ int mt9m111_init(struct sd *sd)
        if (dump_sensor)
                mt9m111_dump_registers(sd);
 
-       return (err < 0) ? err : 0;
+       err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = mt9m111_set_green_balance(&sd->gspca_dev,
+                                        sensor_settings[GREEN_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = mt9m111_set_blue_balance(&sd->gspca_dev,
+                                        sensor_settings[BLUE_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = mt9m111_set_red_balance(&sd->gspca_dev,
+                                       sensor_settings[RED_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
 }
 
-int mt9m111_power_down(struct sd *sd)
+int mt9m111_start(struct sd *sd)
 {
-       return 0;
+       int i, err = 0;
+       u8 data[2];
+       struct cam *cam = &sd->gspca_dev.cam;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
+       int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
+
+       for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) {
+               if (start_mt9m111[i][0] == BRIDGE) {
+                       err = m5602_write_bridge(sd,
+                               start_mt9m111[i][1],
+                               start_mt9m111[i][2]);
+               } else {
+                       data[0] = start_mt9m111[i][2];
+                       data[1] = start_mt9m111[i][3];
+                       err = m5602_write_sensor(sd,
+                               start_mt9m111[i][1], data, 2);
+               }
+       }
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
+                                (width >> 8) & 0xff);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+       if (err < 0)
+               return err;
+
+       switch (width) {
+       case 640:
+               PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+               data[0] = MT9M111_RMB_OVER_SIZED;
+               data[1] = MT9M111_RMB_ROW_SKIP_2X |
+                         MT9M111_RMB_COLUMN_SKIP_2X |
+                         (sensor_settings[VFLIP_IDX] << 0) |
+                         (sensor_settings[HFLIP_IDX] << 1);
+
+               err = m5602_write_sensor(sd,
+                                        MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+               break;
+
+       case 320:
+               PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
+               data[0] = MT9M111_RMB_OVER_SIZED;
+               data[1] = MT9M111_RMB_ROW_SKIP_4X |
+                               MT9M111_RMB_COLUMN_SKIP_4X |
+                               (sensor_settings[VFLIP_IDX] << 0) |
+                               (sensor_settings[HFLIP_IDX] << 1);
+               err = m5602_write_sensor(sd,
+                                        MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+               break;
+       }
+       return err;
 }
 
-int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+void mt9m111_disconnect(struct sd *sd)
+{
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
+}
+
+static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
-                                 data, 2);
-       *val = data[0] & MT9M111_RMB_MIRROR_ROWS;
+       *val = sensor_settings[VFLIP_IDX];
        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
 
+       sensor_settings[VFLIP_IDX] = val;
+
+       /* The mt9m111 is flipped by default */
+       val = !val;
+
        /* Set the correct page map */
        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
        if (err < 0)
@@ -186,34 +396,37 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        if (err < 0)
                return err;
 
-       data[0] = (data[0] & 0xfe) | val;
+       data[1] = (data[1] & 0xfe) | val;
        err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                   data, 2);
        return err;
 }
 
-int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
-                                 data, 2);
-       *val = data[0] & MT9M111_RMB_MIRROR_COLS;
+       *val = sensor_settings[HFLIP_IDX];
        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
 
+       sensor_settings[HFLIP_IDX] = val;
+
+       /* The mt9m111 is flipped by default */
+       val = !val;
+
        /* Set the correct page map */
        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
        if (err < 0)
@@ -223,36 +436,62 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        if (err < 0)
                return err;
 
-       data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
+       data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
        err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                        data, 2);
        return err;
 }
 
-int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err, tmp;
-       u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
-       tmp = ((data[1] << 8) | data[0]);
+       *val = sensor_settings[GAIN_IDX];
+       PDEBUG(D_V4L2, "Read gain %d", *val);
 
-       *val = ((tmp & (1 << 10)) * 2) |
-             ((tmp & (1 <<  9)) * 2) |
-             ((tmp & (1 <<  8)) * 2) |
-              (tmp & 0x7f);
+       return 0;
+}
 
-       PDEBUG(D_V4L2, "Read gain %d", *val);
+static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                         __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+       int err;
+       u8 data[2];
+
+       err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
+       if (err < 0)
+               return err;
+
+       sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
+       data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
 
+       err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
+
+       PDEBUG(D_V4L2, "Set auto white balance %d", val);
        return err;
 }
 
-int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                         __s32 *val) {
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read auto white balance %d", *val);
+       return 0;
+}
+
+static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err, tmp;
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[GAIN_IDX] = val;
 
        /* Set the correct page map */
        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@@ -275,8 +514,8 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        else
                tmp = val;
 
-       data[1] = (tmp & 0xff00) >> 8;
-       data[0] = (tmp & 0xff);
+       data[1] = (tmp & 0xff);
+       data[0] = (tmp & 0xff00) >> 8;
        PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
               data[1], data[0]);
 
@@ -286,6 +525,89 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
+static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[GREEN_BALANCE_IDX] = val;
+       data[1] = (val & 0xff);
+       data[0] = (val & 0xff00) >> 8;
+
+       PDEBUG(D_V4L2, "Set green balance %d", val);
+       err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN,
+                                data, 2);
+       if (err < 0)
+               return err;
+
+       return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN,
+                                 data, 2);
+}
+
+static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GREEN_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read green balance %d", *val);
+       return 0;
+}
+
+static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[BLUE_BALANCE_IDX] = val;
+       data[1] = (val & 0xff);
+       data[0] = (val & 0xff00) >> 8;
+
+       PDEBUG(D_V4L2, "Set blue balance %d", val);
+
+       return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN,
+                                 data, 2);
+}
+
+static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[BLUE_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read blue balance %d", *val);
+       return 0;
+}
+
+static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[RED_BALANCE_IDX] = val;
+       data[1] = (val & 0xff);
+       data[0] = (val & 0xff00) >> 8;
+
+       PDEBUG(D_V4L2, "Set red balance %d", val);
+
+       return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN,
+                                 data, 2);
+}
+
+static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[RED_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read red balance %d", *val);
+       return 0;
+}
+
 static void mt9m111_dump_registers(struct sd *sd)
 {
        u8 address, value[2] = {0x00, 0x00};
index 00c6db02bdb7724987e4d38f41cdc13ab94d93f3..b3de77823091bf56ab37913e4122dd8fbc5e9ddf 100644 (file)
@@ -37,7 +37,6 @@
 #define MT9M111_SC_VBLANK_CONTEXT_A            0x08
 #define MT9M111_SC_SHUTTER_WIDTH               0x09
 #define MT9M111_SC_ROW_SPEED                   0x0a
-
 #define MT9M111_SC_EXTRA_DELAY                 0x0b
 #define MT9M111_SC_SHUTTER_DELAY               0x0c
 #define MT9M111_SC_RESET                       0x0d
@@ -50,9 +49,6 @@
 #define MT9M111_SC_GREEN_2_GAIN                        0x2e
 #define MT9M111_SC_GLOBAL_GAIN                 0x2f
 
-#define MT9M111_RMB_MIRROR_ROWS                        (1 << 0)
-#define MT9M111_RMB_MIRROR_COLS                        (1 << 1)
-
 #define MT9M111_CONTEXT_CONTROL                        0xc8
 #define MT9M111_PAGE_MAP                       0xf0
 #define MT9M111_BYTEWISE_ADDRESS               0xf1
 #define MT9M111_COLORPIPE                      0x01
 #define MT9M111_CAMERA_CONTROL                 0x02
 
+#define MT9M111_RESET                          (1 << 0)
+#define MT9M111_RESTART                                (1 << 1)
+#define MT9M111_ANALOG_STANDBY                 (1 << 2)
+#define MT9M111_CHIP_ENABLE                    (1 << 3)
+#define MT9M111_CHIP_DISABLE                   (0 << 3)
+#define MT9M111_OUTPUT_DISABLE                 (1 << 4)
+#define MT9M111_SHOW_BAD_FRAMES                        (1 << 0)
+#define MT9M111_RESTART_BAD_FRAMES             (1 << 1)
+#define MT9M111_SYNCHRONIZE_CHANGES            (1 << 7)
+
+#define MT9M111_RMB_OVER_SIZED                 (1 << 0)
+#define MT9M111_RMB_MIRROR_ROWS                        (1 << 0)
+#define MT9M111_RMB_MIRROR_COLS                        (1 << 1)
+#define MT9M111_RMB_ROW_SKIP_2X                        (1 << 2)
+#define MT9M111_RMB_COLUMN_SKIP_2X             (1 << 3)
+#define MT9M111_RMB_ROW_SKIP_4X                        (1 << 4)
+#define MT9M111_RMB_COLUMN_SKIP_4X             (1 << 5)
+
+#define MT9M111_COLOR_MATRIX_BYPASS            (1 << 4)
+#define MT9M111_SEL_CONTEXT_B                  (1 << 3)
+
+#define MT9M111_TRISTATE_PIN_IN_STANDBY                (1 << 1)
+#define MT9M111_SOC_SOFT_STANDBY               (1 << 0)
+
+#define MT9M111_2D_DEFECT_CORRECTION_ENABLE    (1 << 0)
+
 #define INITIAL_MAX_GAIN                       64
-#define DEFAULT_GAIN                           283
+#define MT9M111_DEFAULT_GAIN                   283
+#define MT9M111_GREEN_GAIN_DEFAULT             0x20
+#define MT9M111_BLUE_GAIN_DEFAULT              0x20
+#define MT9M111_RED_GAIN_DEFAULT               0x20
 
 /*****************************************************************************/
 
@@ -85,16 +110,10 @@ extern int dump_sensor;
 
 int mt9m111_probe(struct sd *sd);
 int mt9m111_init(struct sd *sd);
-int mt9m111_power_down(struct sd *sd);
+int mt9m111_start(struct sd *sd);
+void mt9m111_disconnect(struct sd *sd);
 
-int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-
-const static struct m5602_sensor mt9m111 = {
+static const struct m5602_sensor mt9m111 = {
        .name = "MT9M111",
 
        .i2c_slave_id = 0xba,
@@ -102,7 +121,8 @@ const static struct m5602_sensor mt9m111 = {
 
        .probe = mt9m111_probe,
        .init = mt9m111_init,
-       .power_down = mt9m111_power_down
+       .disconnect = mt9m111_disconnect,
+       .start = mt9m111_start,
 };
 
 static const unsigned char preinit_mt9m111[][4] =
@@ -117,7 +137,14 @@ static const unsigned char preinit_mt9m111[][4] =
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
 
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
+       {SENSOR, MT9M111_SC_RESET,
+               MT9M111_RESET |
+               MT9M111_RESTART |
+               MT9M111_ANALOG_STANDBY |
+               MT9M111_CHIP_DISABLE,
+               MT9M111_SHOW_BAD_FRAMES |
+               MT9M111_RESTART_BAD_FRAMES |
+               MT9M111_SYNCHRONIZE_CHANGES},
 
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
@@ -145,731 +172,42 @@ static const unsigned char init_mt9m111[][4] =
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xde},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
 
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0xff, 0xff},
-
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
-       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
-       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
-
-       {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
-       {SENSOR, 0xd0, 0x00, 0x40},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
-       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-
-       {SENSOR, 0x33, 0x03, 0x49},
-       {SENSOR, 0x34, 0xc0, 0x19},
-       {SENSOR, 0x3f, 0x20, 0x20},
-       {SENSOR, 0x40, 0x20, 0x20},
-       {SENSOR, 0x5a, 0xc0, 0x0a},
-       {SENSOR, 0x70, 0x7b, 0x0a},
-       {SENSOR, 0x71, 0xff, 0x00},
-       {SENSOR, 0x72, 0x19, 0x0e},
-       {SENSOR, 0x73, 0x18, 0x0f},
-       {SENSOR, 0x74, 0x57, 0x32},
-       {SENSOR, 0x75, 0x56, 0x34},
-       {SENSOR, 0x76, 0x73, 0x35},
-       {SENSOR, 0x77, 0x30, 0x12},
-       {SENSOR, 0x78, 0x79, 0x02},
-       {SENSOR, 0x79, 0x75, 0x06},
-       {SENSOR, 0x7a, 0x77, 0x0a},
-       {SENSOR, 0x7b, 0x78, 0x09},
-       {SENSOR, 0x7c, 0x7d, 0x06},
-       {SENSOR, 0x7d, 0x31, 0x10},
-       {SENSOR, 0x7e, 0x00, 0x7e},
-       {SENSOR, 0x80, 0x59, 0x04},
-       {SENSOR, 0x81, 0x59, 0x04},
-       {SENSOR, 0x82, 0x57, 0x0a},
-       {SENSOR, 0x83, 0x58, 0x0b},
-       {SENSOR, 0x84, 0x47, 0x0c},
-       {SENSOR, 0x85, 0x48, 0x0e},
-       {SENSOR, 0x86, 0x5b, 0x02},
-       {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
-       {SENSOR, 0x60, 0x00, 0x80},
-       {SENSOR, 0x61, 0x00, 0x00},
-       {SENSOR, 0x62, 0x00, 0x00},
-       {SENSOR, 0x63, 0x00, 0x00},
-       {SENSOR, 0x64, 0x00, 0x00},
-
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
-       {SENSOR, 0x30, 0x04, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
-       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
-       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
-       {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
-       {SENSOR, 0xd0, 0x00, 0x40},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
-       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-
-       {SENSOR, 0x33, 0x03, 0x49},
-       {SENSOR, 0x34, 0xc0, 0x19},
-       {SENSOR, 0x3f, 0x20, 0x20},
-       {SENSOR, 0x40, 0x20, 0x20},
-       {SENSOR, 0x5a, 0xc0, 0x0a},
-       {SENSOR, 0x70, 0x7b, 0x0a},
-       {SENSOR, 0x71, 0xff, 0x00},
-       {SENSOR, 0x72, 0x19, 0x0e},
-       {SENSOR, 0x73, 0x18, 0x0f},
-       {SENSOR, 0x74, 0x57, 0x32},
-       {SENSOR, 0x75, 0x56, 0x34},
-       {SENSOR, 0x76, 0x73, 0x35},
-       {SENSOR, 0x77, 0x30, 0x12},
-       {SENSOR, 0x78, 0x79, 0x02},
-       {SENSOR, 0x79, 0x75, 0x06},
-       {SENSOR, 0x7a, 0x77, 0x0a},
-       {SENSOR, 0x7b, 0x78, 0x09},
-       {SENSOR, 0x7c, 0x7d, 0x06},
-       {SENSOR, 0x7d, 0x31, 0x10},
-       {SENSOR, 0x7e, 0x00, 0x7e},
-       {SENSOR, 0x80, 0x59, 0x04},
-       {SENSOR, 0x81, 0x59, 0x04},
-       {SENSOR, 0x82, 0x57, 0x0a},
-       {SENSOR, 0x83, 0x58, 0x0b},
-       {SENSOR, 0x84, 0x47, 0x0c},
-       {SENSOR, 0x85, 0x48, 0x0e},
-       {SENSOR, 0x86, 0x5b, 0x02},
-       {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
-       {SENSOR, 0x60, 0x00, 0x80},
-       {SENSOR, 0x61, 0x00, 0x00},
-       {SENSOR, 0x62, 0x00, 0x00},
-       {SENSOR, 0x63, 0x00, 0x00},
-       {SENSOR, 0x64, 0x00, 0x00},
-
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
-       {SENSOR, 0x30, 0x04, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
        {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
 
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
        {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
        {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00,
+                       MT9M111_CP_OPERATING_MODE_CTL},
        {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00,
+                               MT9M111_2D_DEFECT_CORRECTION_ENABLE},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00,
+                               MT9M111_2D_DEFECT_CORRECTION_ENABLE},
        {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
        {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
        {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
        {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
        {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
        {SENSOR, 0xd0, 0x00, 0x40},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
-       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-
-       {SENSOR, 0x33, 0x03, 0x49},
-       {SENSOR, 0x34, 0xc0, 0x19},
-       {SENSOR, 0x3f, 0x20, 0x20},
-       {SENSOR, 0x40, 0x20, 0x20},
-       {SENSOR, 0x5a, 0xc0, 0x0a},
-       {SENSOR, 0x70, 0x7b, 0x0a},
-       {SENSOR, 0x71, 0xff, 0x00},
-       {SENSOR, 0x72, 0x19, 0x0e},
-       {SENSOR, 0x73, 0x18, 0x0f},
-       {SENSOR, 0x74, 0x57, 0x32},
-       {SENSOR, 0x75, 0x56, 0x34},
-       {SENSOR, 0x76, 0x73, 0x35},
-       {SENSOR, 0x77, 0x30, 0x12},
-       {SENSOR, 0x78, 0x79, 0x02},
-       {SENSOR, 0x79, 0x75, 0x06},
-       {SENSOR, 0x7a, 0x77, 0x0a},
-       {SENSOR, 0x7b, 0x78, 0x09},
-       {SENSOR, 0x7c, 0x7d, 0x06},
-       {SENSOR, 0x7d, 0x31, 0x10},
-       {SENSOR, 0x7e, 0x00, 0x7e},
-       {SENSOR, 0x80, 0x59, 0x04},
-       {SENSOR, 0x81, 0x59, 0x04},
-       {SENSOR, 0x82, 0x57, 0x0a},
-       {SENSOR, 0x83, 0x58, 0x0b},
-       {SENSOR, 0x84, 0x47, 0x0c},
-       {SENSOR, 0x85, 0x48, 0x0e},
-       {SENSOR, 0x86, 0x5b, 0x02},
-       {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
-       {SENSOR, 0x60, 0x00, 0x80},
-       {SENSOR, 0x61, 0x00, 0x00},
-       {SENSOR, 0x62, 0x00, 0x00},
-       {SENSOR, 0x63, 0x00, 0x00},
-       {SENSOR, 0x64, 0x00, 0x00},
 
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
-       {SENSOR, 0x30, 0x04, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
-       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
-       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0xd0, 0x00, 0x40},
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
        {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
        {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-
-       {SENSOR, 0x33, 0x03, 0x49},
-       {SENSOR, 0x34, 0xc0, 0x19},
-       {SENSOR, 0x3f, 0x20, 0x20},
-       {SENSOR, 0x40, 0x20, 0x20},
-       {SENSOR, 0x5a, 0xc0, 0x0a},
-       {SENSOR, 0x70, 0x7b, 0x0a},
-       {SENSOR, 0x71, 0xff, 0x00},
-       {SENSOR, 0x72, 0x19, 0x0e},
-       {SENSOR, 0x73, 0x18, 0x0f},
-       {SENSOR, 0x74, 0x57, 0x32},
-       {SENSOR, 0x75, 0x56, 0x34},
-       {SENSOR, 0x76, 0x73, 0x35},
-       {SENSOR, 0x77, 0x30, 0x12},
-       {SENSOR, 0x78, 0x79, 0x02},
-       {SENSOR, 0x79, 0x75, 0x06},
-       {SENSOR, 0x7a, 0x77, 0x0a},
-       {SENSOR, 0x7b, 0x78, 0x09},
-       {SENSOR, 0x7c, 0x7d, 0x06},
-       {SENSOR, 0x7d, 0x31, 0x10},
-       {SENSOR, 0x7e, 0x00, 0x7e},
-       {SENSOR, 0x80, 0x59, 0x04},
-       {SENSOR, 0x81, 0x59, 0x04},
-       {SENSOR, 0x82, 0x57, 0x0a},
-       {SENSOR, 0x83, 0x58, 0x0b},
-       {SENSOR, 0x84, 0x47, 0x0c},
-       {SENSOR, 0x85, 0x48, 0x0e},
-       {SENSOR, 0x86, 0x5b, 0x02},
-       {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
-       {SENSOR, 0x60, 0x00, 0x80},
-       {SENSOR, 0x61, 0x00, 0x00},
-       {SENSOR, 0x62, 0x00, 0x00},
-       {SENSOR, 0x63, 0x00, 0x00},
-       {SENSOR, 0x64, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
-       {SENSOR, 0x30, 0x04, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe3, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xe6},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
 
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
-       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
-       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0xd0, 0x00, 0x40},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
-       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-
        {SENSOR, 0x33, 0x03, 0x49},
        {SENSOR, 0x34, 0xc0, 0x19},
        {SENSOR, 0x3f, 0x20, 0x20},
@@ -898,25 +236,29 @@ static const unsigned char init_mt9m111[][4] =
        {SENSOR, 0x85, 0x48, 0x0e},
        {SENSOR, 0x86, 0x5b, 0x02},
        {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, MT9M111_SEL_CONTEXT_B},
        {SENSOR, 0x60, 0x00, 0x80},
        {SENSOR, 0x61, 0x00, 0x00},
        {SENSOR, 0x62, 0x00, 0x00},
        {SENSOR, 0x63, 0x00, 0x00},
        {SENSOR, 0x64, 0x00, 0x00},
 
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
+       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, /* 13 */
+       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, /* 18 */
+       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, /* 1024 */
+       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, /* 1296 */
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, /* 352 */
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, /* 17 */
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, /* 352 */
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, /* 17 */
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, /* 271 */
        {SENSOR, 0x30, 0x04, 0x00},
+       /* Set number of blank rows chosen to 400 */
+       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
+};
 
+static const unsigned char start_mt9m111[][4] =
+{
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -928,25 +270,6 @@ static const unsigned char init_mt9m111[][4] =
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, /* 639*/
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       /* Set number of blank rows chosen to 400 */
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
-       /* Set the global gain to 283 (of 512) */
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x03, 0x63}
 };
 
 #endif
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/video/gspca/m5602/m5602_ov7660.c
new file mode 100644 (file)
index 0000000..7aafeb7
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Driver for the ov7660 sensor
+ *
+ * Copyright (C) 2009 Erik Andrén
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_ov7660.h"
+
+static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+const static struct ctrl ov7660_ctrls[] = {
+#define GAIN_IDX 1
+       {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "gain",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = OV7660_DEFAULT_GAIN,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = ov7660_set_gain,
+               .get = ov7660_get_gain
+       },
+};
+
+static struct v4l2_pix_format ov7660_modes[] = {
+       {
+               640,
+               480,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       640 * 480,
+               .bytesperline = 640,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
+       }
+};
+
+static void ov7660_dump_registers(struct sd *sd);
+
+int ov7660_probe(struct sd *sd)
+{
+       int err = 0, i;
+       u8 prod_id = 0, ver_id = 0;
+
+       s32 *sensor_settings;
+
+       if (force_sensor) {
+               if (force_sensor == OV7660_SENSOR) {
+                       info("Forcing an %s sensor", ov7660.name);
+                       goto sensor_found;
+               }
+               /* If we want to force another sensor,
+               don't try to probe this one */
+               return -ENODEV;
+       }
+
+       /* Do the preinit */
+       for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
+               u8 data[2];
+
+               if (preinit_ov7660[i][0] == BRIDGE) {
+                       err = m5602_write_bridge(sd,
+                               preinit_ov7660[i][1],
+                               preinit_ov7660[i][2]);
+               } else {
+                       data[0] = preinit_ov7660[i][2];
+                       err = m5602_write_sensor(sd,
+                               preinit_ov7660[i][1], data, 1);
+               }
+       }
+       if (err < 0)
+               return err;
+
+       if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
+               return -ENODEV;
+
+       if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
+               return -ENODEV;
+
+       info("Sensor reported 0x%x%x", prod_id, ver_id);
+
+       if ((prod_id == 0x76) && (ver_id == 0x60)) {
+               info("Detected a ov7660 sensor");
+               goto sensor_found;
+       }
+       return -ENODEV;
+
+sensor_found:
+       sensor_settings = kmalloc(
+               ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
+       if (!sensor_settings)
+               return -ENOMEM;
+
+       sd->gspca_dev.cam.cam_mode = ov7660_modes;
+       sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
+       sd->desc->ctrls = ov7660_ctrls;
+       sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
+
+       for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
+               sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
+       sd->sensor_priv = sensor_settings;
+
+       return 0;
+}
+
+int ov7660_init(struct sd *sd)
+{
+       int i, err = 0;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       /* Init the sensor */
+       for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
+               u8 data[2];
+
+               if (init_ov7660[i][0] == BRIDGE) {
+                       err = m5602_write_bridge(sd,
+                               init_ov7660[i][1],
+                               init_ov7660[i][2]);
+               } else {
+                       data[0] = init_ov7660[i][2];
+                       err = m5602_write_sensor(sd,
+                                       init_ov7660[i][1], data, 1);
+               }
+       }
+
+       if (dump_sensor)
+               ov7660_dump_registers(sd);
+
+       err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       if (err < 0)
+               return err;
+
+       return err;
+}
+
+int ov7660_start(struct sd *sd)
+{
+       return 0;
+}
+
+int ov7660_stop(struct sd *sd)
+{
+       return 0;
+}
+
+void ov7660_disconnect(struct sd *sd)
+{
+       ov7660_stop(sd);
+
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
+}
+
+static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GAIN_IDX];
+       PDEBUG(D_V4L2, "Read gain %d", *val);
+       return 0;
+}
+
+static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       PDEBUG(D_V4L2, "Setting gain to %d", val);
+
+       sensor_settings[GAIN_IDX] = val;
+
+       err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
+       return err;
+}
+
+static void ov7660_dump_registers(struct sd *sd)
+{
+       int address;
+       info("Dumping the ov7660 register state");
+       for (address = 0; address < 0xa9; address++) {
+               u8 value;
+               m5602_read_sensor(sd, address, &value, 1);
+               info("register 0x%x contains 0x%x",
+                    address, value);
+       }
+
+       info("ov7660 register state dump complete");
+
+       info("Probing for which registers that are read/write");
+       for (address = 0; address < 0xff; address++) {
+               u8 old_value, ctrl_value;
+               u8 test_value[2] = {0xff, 0xff};
+
+               m5602_read_sensor(sd, address, &old_value, 1);
+               m5602_write_sensor(sd, address, test_value, 1);
+               m5602_read_sensor(sd, address, &ctrl_value, 1);
+
+               if (ctrl_value == test_value[0])
+                       info("register 0x%x is writeable", address);
+               else
+                       info("register 0x%x is read only", address);
+
+               /* Restore original value */
+               m5602_write_sensor(sd, address, &old_value, 1);
+       }
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h
new file mode 100644 (file)
index 0000000..3f2c169
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Driver for the ov7660 sensor
+ *
+ * Copyright (C) 2009 Erik Andrén
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#ifndef M5602_OV7660_H_
+#define M5602_OV7660_H_
+
+#include "m5602_sensor.h"
+
+#define OV7660_GAIN            0x00
+#define OV7660_BLUE_GAIN       0x01
+#define OV7660_RED_GAIN                0x02
+#define OV7660_VREF            0x03
+#define OV7660_COM1            0x04
+#define OV7660_BAVE            0x05
+#define OV7660_GEAVE           0x06
+#define OV7660_AECHH           0x07
+#define OV7660_RAVE            0x08
+#define OV7660_COM2            0x09
+#define OV7660_PID             0x0a
+#define OV7660_VER             0x0b
+#define OV7660_COM3            0x0c
+#define OV7660_COM4            0x0d
+#define OV7660_COM5            0x0e
+#define OV7660_COM6            0x0f
+#define OV7660_AECH            0x10
+#define OV7660_CLKRC           0x11
+#define OV7660_COM7            0x12
+#define OV7660_COM8            0x13
+#define OV7660_COM9            0x14
+#define OV7660_COM10           0x15
+#define OV7660_RSVD16          0x16
+#define OV7660_HSTART          0x17
+#define OV7660_HSTOP           0x18
+#define OV7660_VSTART          0x19
+#define OV7660_VSTOP           0x1a
+#define OV7660_PSHFT           0x1b
+#define OV7660_MIDH            0x1c
+#define OV7660_MIDL            0x1d
+#define OV7660_MVFP            0x1e
+#define OV7660_LAEC            0x1f
+#define OV7660_BOS             0x20
+#define OV7660_GBOS            0x21
+#define OV7660_GROS            0x22
+#define OV7660_ROS             0x23
+#define OV7660_AEW             0x24
+#define OV7660_AEB             0x25
+#define OV7660_VPT             0x26
+#define OV7660_BBIAS           0x27
+#define OV7660_GbBIAS          0x28
+#define OV7660_RSVD29          0x29
+#define OV7660_RBIAS           0x2c
+#define OV7660_HREF            0x32
+#define OV7660_ADC             0x37
+#define OV7660_OFON            0x39
+#define OV7660_TSLB            0x3a
+#define OV7660_COM12           0x3c
+#define OV7660_COM13           0x3d
+#define OV7660_LCC1            0x62
+#define OV7660_LCC2            0x63
+#define OV7660_LCC3            0x64
+#define OV7660_LCC4            0x65
+#define OV7660_LCC5            0x66
+#define OV7660_HV              0x69
+#define OV7660_RSVDA1          0xa1
+
+#define OV7660_DEFAULT_GAIN            0x0e
+#define OV7660_DEFAULT_RED_GAIN        0x80
+#define OV7660_DEFAULT_BLUE_GAIN       0x80
+#define OV7660_DEFAULT_SATURATION      0x00
+#define OV7660_DEFAULT_EXPOSURE        0x20
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+
+int ov7660_probe(struct sd *sd);
+int ov7660_init(struct sd *sd);
+int ov7660_start(struct sd *sd);
+int ov7660_stop(struct sd *sd);
+void ov7660_disconnect(struct sd *sd);
+
+const static struct m5602_sensor ov7660 = {
+       .name = "ov7660",
+       .i2c_slave_id = 0x42,
+       .i2c_regW = 1,
+       .probe = ov7660_probe,
+       .init = ov7660_init,
+       .start = ov7660_start,
+       .stop = ov7660_stop,
+       .disconnect = ov7660_disconnect,
+};
+
+static const unsigned char preinit_ov7660[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+
+       {SENSOR, OV7660_OFON, 0x0c},
+       {SENSOR, OV7660_COM2, 0x11},
+       {SENSOR, OV7660_COM7, 0x05},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}
+};
+
+static const unsigned char init_ov7660[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+
+       {SENSOR, OV7660_OFON, 0x0c},
+       {SENSOR, OV7660_COM2, 0x11},
+       {SENSOR, OV7660_COM7, 0x05},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+       {SENSOR, OV7660_AECH, OV7660_DEFAULT_EXPOSURE},
+       {SENSOR, OV7660_COM1, 0x00},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
+
+       {SENSOR, OV7660_COM7, 0x80},
+       {SENSOR, OV7660_CLKRC, 0x80},
+       {SENSOR, OV7660_BLUE_GAIN, 0x80},
+       {SENSOR, OV7660_RED_GAIN, 0x80},
+       {SENSOR, OV7660_COM9, 0x4c},
+       {SENSOR, OV7660_OFON, 0x43},
+       {SENSOR, OV7660_COM12, 0x28},
+       {SENSOR, OV7660_COM8, 0x00},
+       {SENSOR, OV7660_COM10, 0x40},
+       {SENSOR, OV7660_HSTART, 0x0c},
+       {SENSOR, OV7660_HSTOP, 0x61},
+       {SENSOR, OV7660_HREF, 0xa4},
+       {SENSOR, OV7660_PSHFT, 0x0b},
+       {SENSOR, OV7660_VSTART, 0x01},
+       {SENSOR, OV7660_VSTOP, 0x7a},
+       {SENSOR, OV7660_VREF, 0x00},
+       {SENSOR, OV7660_COM7, 0x05},
+       {SENSOR, OV7660_COM6, 0x4b},
+       {SENSOR, OV7660_BBIAS, 0x98},
+       {SENSOR, OV7660_GbBIAS, 0x98},
+       {SENSOR, OV7660_RSVD29, 0x98},
+       {SENSOR, OV7660_RBIAS, 0x98},
+       {SENSOR, OV7660_COM1, 0x00},
+       {SENSOR, OV7660_AECH, 0x00},
+       {SENSOR, OV7660_AECHH, 0x00},
+       {SENSOR, OV7660_ADC, 0x04},
+       {SENSOR, OV7660_COM13, 0x00},
+       {SENSOR, OV7660_RSVDA1, 0x23},
+       {SENSOR, OV7660_TSLB, 0x0d},
+       {SENSOR, OV7660_HV, 0x80},
+       {SENSOR, OV7660_LCC1, 0x00},
+       {SENSOR, OV7660_LCC2, 0x00},
+       {SENSOR, OV7660_LCC3, 0x10},
+       {SENSOR, OV7660_LCC4, 0x40},
+       {SENSOR, OV7660_LCC5, 0x01},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x08},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x27}, /* 39 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xa7}, /* 679 */
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+       {SENSOR, OV7660_AECH, 0x20},
+       {SENSOR, OV7660_COM1, 0x00},
+       {SENSOR, OV7660_OFON, 0x0c},
+       {SENSOR, OV7660_COM2, 0x11},
+       {SENSOR, OV7660_COM7, 0x05},
+       {SENSOR, OV7660_BLUE_GAIN, 0x80},
+       {SENSOR, OV7660_RED_GAIN, 0x80},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}
+};
+
+#endif
index fc4548fd441dc1674d807628b0a68ad3bca8aca6..c2739d6605a14612cd3db4a20124bd6d8be6b411 100644 (file)
 
 #include "m5602_ov9650.h"
 
+static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 *val);
+static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val);
+static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
+
 /* Vertically and horizontally flips the image if matched, needed for machines
    where the sensor is mounted upside down */
 static
     const
        struct dmi_system_id ov9650_flip_dmi_table[] = {
        {
-               .ident = "ASUS A6VC",
+               .ident = "ASUS A6Ja",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
                }
        },
        {
-               .ident = "ASUS A6VM",
+               .ident = "ASUS A6JC",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
                }
        },
        {
-               .ident = "ASUS A6JC",
+               .ident = "ASUS A6K",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6K")
                }
        },
        {
-               .ident = "ASUS A6Ja",
+               .ident = "ASUS A6Kt",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
                }
        },
        {
-               .ident = "ASUS A6Kt",
+               .ident = "ASUS A6VA",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
+               }
+       },
+       {
+
+               .ident = "ASUS A6VC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
+               }
+       },
+       {
+               .ident = "ASUS A6VM",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+               }
+       },
+       {
+               .ident = "ASUS A7V",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A7V")
                }
        },
        {
@@ -68,7 +111,7 @@ static
        {}
 };
 
-const static struct ctrl ov9650_ctrls[] = {
+static const struct ctrl ov9650_ctrls[] = {
 #define EXPOSURE_IDX 0
        {
                {
@@ -102,6 +145,7 @@ const static struct ctrl ov9650_ctrls[] = {
 #define RED_BALANCE_IDX 2
        {
                {
+                       .id             = V4L2_CID_RED_BALANCE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
                        .name           = "red balance",
                        .minimum        = 0x00,
@@ -116,6 +160,7 @@ const static struct ctrl ov9650_ctrls[] = {
 #define BLUE_BALANCE_IDX 3
        {
                {
+                       .id             = V4L2_CID_BLUE_BALANCE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
                        .name           = "blue balance",
                        .minimum        = 0x00,
@@ -182,7 +227,22 @@ const static struct ctrl ov9650_ctrls[] = {
                },
                .set = ov9650_set_auto_gain,
                .get = ov9650_get_auto_gain
+       },
+#define AUTO_EXPOSURE_IDX 8
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE_AUTO,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto exposure",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
+               },
+               .set = ov9650_set_auto_exposure,
+               .get = ov9650_get_auto_exposure
        }
+
 };
 
 static struct v4l2_pix_format ov9650_modes[] = {
@@ -289,12 +349,6 @@ sensor_found:
        for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
                sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
        sd->sensor_priv = sensor_settings;
-
-       if (dmi_check_system(ov9650_flip_dmi_table) && !err) {
-               info("vflip quirk active");
-               sensor_settings[VFLIP_IDX] = 1;
-       }
-
        return 0;
 }
 
@@ -316,7 +370,8 @@ int ov9650_init(struct sd *sd)
                        err = m5602_write_bridge(sd, init_ov9650[i][1], data);
        }
 
-       err = ov9650_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
+       err = ov9650_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
        if (err < 0)
                return err;
 
@@ -324,11 +379,13 @@ int ov9650_init(struct sd *sd)
        if (err < 0)
                return err;
 
-       err = ov9650_set_red_balance(&sd->gspca_dev, sensor_settings[RED_BALANCE_IDX]);
+       err = ov9650_set_red_balance(&sd->gspca_dev,
+                                     sensor_settings[RED_BALANCE_IDX]);
        if (err < 0)
                return err;
 
-       err = ov9650_set_blue_balance(&sd->gspca_dev, sensor_settings[BLUE_BALANCE_IDX]);
+       err = ov9650_set_blue_balance(&sd->gspca_dev,
+                                      sensor_settings[BLUE_BALANCE_IDX]);
        if (err < 0)
                return err;
 
@@ -340,11 +397,18 @@ int ov9650_init(struct sd *sd)
        if (err < 0)
                return err;
 
-       err = ov9650_set_auto_white_balance(&sd->gspca_dev, sensor_settings[AUTO_WHITE_BALANCE_IDX]);
+       err = ov9650_set_auto_exposure(&sd->gspca_dev,
+                               sensor_settings[AUTO_EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = ov9650_set_auto_white_balance(&sd->gspca_dev,
+                               sensor_settings[AUTO_WHITE_BALANCE_IDX]);
        if (err < 0)
                return err;
 
-       err = ov9650_set_auto_gain(&sd->gspca_dev, sensor_settings[AUTO_GAIN_CTRL_IDX]);
+       err = ov9650_set_auto_gain(&sd->gspca_dev,
+                               sensor_settings[AUTO_GAIN_CTRL_IDX]);
        return err;
 }
 
@@ -360,7 +424,10 @@ int ov9650_start(struct sd *sd)
        int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
        int hor_offs = OV9650_LEFT_OFFSET;
 
-       if (sensor_settings[VFLIP_IDX])
+       if ((!dmi_check_system(ov9650_flip_dmi_table) &&
+               sensor_settings[VFLIP_IDX]) ||
+               (dmi_check_system(ov9650_flip_dmi_table) &&
+               !sensor_settings[VFLIP_IDX]))
                ver_offs--;
 
        if (width <= 320)
@@ -406,6 +473,14 @@ int ov9650_start(struct sd *sd)
        if (err < 0)
                return err;
 
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
+       if (err < 0)
+               return err;
+
        err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
                                 (hor_offs >> 8) & 0xff);
        if (err < 0)
@@ -425,6 +500,10 @@ int ov9650_start(struct sd *sd)
        if (err < 0)
                return err;
 
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+       if (err < 0)
+               return err;
+
        switch (width) {
        case 640:
                PDEBUG(D_V4L2, "Configuring camera for VGA mode");
@@ -467,32 +546,15 @@ int ov9650_stop(struct sd *sd)
        return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
 }
 
-int ov9650_power_down(struct sd *sd)
-{
-       int i, err = 0;
-       for (i = 0; i < ARRAY_SIZE(power_down_ov9650) && !err; i++) {
-               u8 data = power_down_ov9650[i][2];
-               if (power_down_ov9650[i][0] == SENSOR)
-                       err = m5602_write_sensor(sd,
-                                           power_down_ov9650[i][1], &data, 1);
-               else
-                       err = m5602_write_bridge(sd, power_down_ov9650[i][1],
-                                                data);
-       }
-
-       return err;
-}
-
 void ov9650_disconnect(struct sd *sd)
 {
        ov9650_stop(sd);
-       ov9650_power_down(sd);
 
        sd->sensor = NULL;
        kfree(sd->sensor_priv);
 }
 
-int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -502,7 +564,7 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -532,7 +594,7 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -542,7 +604,7 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -573,7 +635,7 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -583,7 +645,7 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -599,7 +661,7 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -610,7 +672,7 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -626,7 +688,7 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -636,7 +698,7 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -646,13 +708,20 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
 
        sensor_settings[HFLIP_IDX] = val;
-       i2c_data = ((val & 0x01) << 5) | (sensor_settings[VFLIP_IDX] << 4);
+
+       if (!dmi_check_system(ov9650_flip_dmi_table))
+               i2c_data = ((val & 0x01) << 5) |
+                               (sensor_settings[VFLIP_IDX] << 4);
+       else
+               i2c_data = ((val & 0x01) << 5) |
+                               (!sensor_settings[VFLIP_IDX] << 4);
+
        err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
 
        return err;
 }
 
-int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -663,7 +732,7 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -673,6 +742,9 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
        sensor_settings[VFLIP_IDX] = val;
 
+       if (dmi_check_system(ov9650_flip_dmi_table))
+               val = !val;
+
        i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
        err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
        if (err < 0)
@@ -685,48 +757,38 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
 
-       *val = sensor_settings[GAIN_IDX];
-       PDEBUG(D_V4L2, "Read gain %d", *val);
-
+       *val = sensor_settings[AUTO_EXPOSURE_IDX];
+       PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
        return 0;
 }
 
-int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
+                                   __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
 
-       PDEBUG(D_V4L2, "Set gain to %d", val);
-
-       sensor_settings[GAIN_IDX] = val;
+       PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
 
-       /* Read the OV9650_VREF register first to avoid
-               corrupting the VREF high and low bits */
-       err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
-       if (err < 0)
-               return err;
-
-       /* Mask away all uninteresting bits */
-       i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F);
-       err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       sensor_settings[AUTO_EXPOSURE_IDX] = val;
+       err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        if (err < 0)
                return err;
 
-       /* The 8 LSBs */
-       i2c_data = val & 0xff;
-       err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+       i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
 
-       return err;
+       return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 }
 
-int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -735,7 +797,8 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -755,7 +818,7 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -765,7 +828,7 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -780,9 +843,8 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
                return err;
 
        i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
-       err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 
-       return err;
+       return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 }
 
 static void ov9650_dump_registers(struct sd *sd)
index fcc54e4c0f4f33d8e764f85960a4d93fa9229b65..c98c40d69e05e8c95ed666c0ef9479525c79962a 100644 (file)
 #define OV9650_SOFT_SLEEP              (1 << 4)
 #define OV9650_OUTPUT_DRIVE_2X         (1 << 0)
 
+#define OV9650_DENOISE_ENABLE          (1 << 5)
+#define OV9650_WHITE_PIXEL_ENABLE      (1 << 1)
+#define OV9650_WHITE_PIXEL_OPTION      (1 << 0)
+
 #define OV9650_LEFT_OFFSET             0x62
 
 #define GAIN_DEFAULT                   0x14
@@ -137,29 +141,9 @@ int ov9650_probe(struct sd *sd);
 int ov9650_init(struct sd *sd);
 int ov9650_start(struct sd *sd);
 int ov9650_stop(struct sd *sd);
-int ov9650_power_down(struct sd *sd);
 void ov9650_disconnect(struct sd *sd);
 
-int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
-
-const static struct m5602_sensor ov9650 = {
+static const struct m5602_sensor ov9650 = {
        .name = "OV9650",
        .i2c_slave_id = 0x60,
        .i2c_regW = 1,
@@ -167,7 +151,6 @@ const static struct m5602_sensor ov9650 = {
        .init = ov9650_init,
        .start = ov9650_start,
        .stop = ov9650_stop,
-       .power_down = ov9650_power_down,
        .disconnect = ov9650_disconnect,
 };
 
@@ -219,7 +202,7 @@ static const unsigned char init_ov9650[][3] =
        /* Reset chip */
        {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
        /* One extra reset is needed in order to make the sensor behave
-          properly when resuming from ram */
+          properly when resuming from ram, could be a timing issue */
        {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
 
        /* Enable double clock */
@@ -229,8 +212,7 @@ static const unsigned char init_ov9650[][3] =
 
        /* Set fast AGC/AEC algorithm with unlimited step size */
        {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC |
-                             OV9650_AEC_UNLIM_STEP_SIZE |
-                             OV9650_AWB_EN | OV9650_AGC_EN},
+                             OV9650_AEC_UNLIM_STEP_SIZE},
 
        {SENSOR, OV9650_CHLF, 0x10},
        {SENSOR, OV9650_ARBLM, 0xbf},
@@ -301,8 +283,11 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_VREF, 0x10},
        {SENSOR, OV9650_ADC, 0x04},
        {SENSOR, OV9650_HV, 0x40},
+
        /* Enable denoise, and white-pixel erase */
-       {SENSOR, OV9650_COM22, 0x23},
+       {SENSOR, OV9650_COM22, OV9650_DENOISE_ENABLE |
+                OV9650_WHITE_PIXEL_ENABLE |
+                OV9650_WHITE_PIXEL_OPTION},
 
        /* Enable VARIOPIXEL */
        {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
@@ -312,26 +297,6 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X},
 };
 
-static const unsigned char power_down_ov9650[][3] =
-{
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {SENSOR, OV9650_COM7, 0x80},
-       {SENSOR, OV9650_OFON, 0xf4},
-       {SENSOR, OV9650_MVFP, 0x80},
-       {SENSOR, OV9650_DBLV, 0x3f},
-       {SENSOR, OV9650_RSVD36, 0x49},
-       {SENSOR, OV9650_COM7, 0x05},
-
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-};
-
 static const unsigned char res_init_ov9650[][3] =
 {
        {SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X},
index eaddf488bad1033d1bd7ed8f3f5190317919f925..8d74d8065b7977cb126d3fb23922830b317671f9 100644 (file)
 
 #include "m5602_po1030.h"
 
+static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val);
+static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 *val);
+static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
+                                        __s32 val);
+static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
+                                        __s32 *val);
+
 static struct v4l2_pix_format po1030_modes[] = {
        {
                640,
@@ -27,11 +50,12 @@ static struct v4l2_pix_format po1030_modes[] = {
                .sizeimage = 640 * 480,
                .bytesperline = 640,
                .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = 0
+               .priv = 2
        }
 };
 
-const static struct ctrl po1030_ctrls[] = {
+static const struct ctrl po1030_ctrls[] = {
+#define GAIN_IDX 0
        {
                {
                        .id             = V4L2_CID_GAIN,
@@ -45,7 +69,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_gain,
                .get = po1030_get_gain
-       }, {
+       },
+#define EXPOSURE_IDX 1
+       {
                {
                        .id             = V4L2_CID_EXPOSURE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -58,7 +84,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_exposure,
                .get = po1030_get_exposure
-       }, {
+       },
+#define RED_BALANCE_IDX 2
+       {
                {
                        .id             = V4L2_CID_RED_BALANCE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -71,7 +99,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_red_balance,
                .get = po1030_get_red_balance
-       }, {
+       },
+#define BLUE_BALANCE_IDX 3
+       {
                {
                        .id             = V4L2_CID_BLUE_BALANCE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -84,7 +114,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_blue_balance,
                .get = po1030_get_blue_balance
-       }, {
+       },
+#define HFLIP_IDX 4
+       {
                {
                        .id             = V4L2_CID_HFLIP,
                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -96,7 +128,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_hflip,
                .get = po1030_get_hflip
-       }, {
+       },
+#define VFLIP_IDX 5
+       {
                {
                        .id             = V4L2_CID_VFLIP,
                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -108,14 +142,58 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_vflip,
                .get = po1030_get_vflip
-       }
+       },
+#define AUTO_WHITE_BALANCE_IDX 6
+       {
+               {
+                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto white balance",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
+               },
+               .set = po1030_set_auto_white_balance,
+               .get = po1030_get_auto_white_balance
+       },
+#define AUTO_EXPOSURE_IDX 7
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE_AUTO,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto exposure",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
+               },
+               .set = po1030_set_auto_exposure,
+               .get = po1030_get_auto_exposure
+       },
+#define GREEN_BALANCE_IDX 8
+       {
+               {
+                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "green balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_GREEN_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = po1030_set_green_balance,
+               .get = po1030_get_green_balance
+       },
 };
 
 static void po1030_dump_registers(struct sd *sd);
 
 int po1030_probe(struct sd *sd)
 {
-       u8 prod_id = 0, ver_id = 0, i;
+       u8 dev_id_h = 0, i;
+       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == PO1030_SENSOR) {
@@ -139,28 +217,36 @@ int po1030_probe(struct sd *sd)
                        m5602_write_bridge(sd, preinit_po1030[i][1], data);
        }
 
-       if (m5602_read_sensor(sd, 0x3, &prod_id, 1))
+       if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1))
                return -ENODEV;
 
-       if (m5602_read_sensor(sd, 0x4, &ver_id, 1))
-               return -ENODEV;
-
-       if ((prod_id == 0x02) && (ver_id == 0xef)) {
+       if (dev_id_h == 0x30) {
                info("Detected a po1030 sensor");
                goto sensor_found;
        }
        return -ENODEV;
 
 sensor_found:
+       sensor_settings = kmalloc(
+               ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL);
+       if (!sensor_settings)
+               return -ENOMEM;
+
        sd->gspca_dev.cam.cam_mode = po1030_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
        sd->desc->ctrls = po1030_ctrls;
        sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
+
+       for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++)
+               sensor_settings[i] = po1030_ctrls[i].qctrl.default_value;
+       sd->sensor_priv = sensor_settings;
+
        return 0;
 }
 
 int po1030_init(struct sd *sd)
 {
+       s32 *sensor_settings = sd->sensor_priv;
        int i, err = 0;
 
        /* Init the sensor */
@@ -185,47 +271,206 @@ int po1030_init(struct sd *sd)
                        return -EINVAL;
                }
        }
+       if (err < 0)
+               return err;
 
        if (dump_sensor)
                po1030_dump_registers(sd);
 
+       err = po1030_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_red_balance(&sd->gspca_dev,
+                                     sensor_settings[RED_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_blue_balance(&sd->gspca_dev,
+                                     sensor_settings[BLUE_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_green_balance(&sd->gspca_dev,
+                                      sensor_settings[GREEN_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_auto_white_balance(&sd->gspca_dev,
+                               sensor_settings[AUTO_WHITE_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_auto_exposure(&sd->gspca_dev,
+                               sensor_settings[AUTO_EXPOSURE_IDX]);
        return err;
 }
 
-int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+int po1030_start(struct sd *sd)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
-       u8 i2c_data;
-       int err;
+       struct cam *cam = &sd->gspca_dev.cam;
+       int i, err = 0;
+       int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
+       int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
+       int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+       u8 data;
+
+       switch (width) {
+       case 320:
+               data = PO1030_SUBSAMPLING;
+               err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = ((width + 3) >> 8) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = (width + 3) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = ((height + 1) >> 8) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = (height + 1) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
+
+               height += 6;
+               width -= 1;
+               break;
+
+       case 640:
+               data = 0;
+               err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = ((width + 7) >> 8) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = (width + 7) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = ((height + 3) >> 8) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = (height + 3) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
+
+               height += 12;
+               width -= 2;
+               break;
+       }
+       err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c);
+       if (err < 0)
+               return err;
 
-       err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_H,
-                                &i2c_data, 1);
+       err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81);
        if (err < 0)
                return err;
-       *val = (i2c_data << 8);
 
-       err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_M,
-                                &i2c_data, 1);
-       *val |= i2c_data;
+       err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82);
+       if (err < 0)
+               return err;
 
-       PDEBUG(D_V4L2, "Exposure read as %d", *val);
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
+                                ((ver_offs >> 8) & 0xff));
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff);
+       if (err < 0)
+               return err;
 
+       err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff));
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
        return err;
 }
 
-int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[EXPOSURE_IDX];
+       PDEBUG(D_V4L2, "Exposure read as %d", *val);
+       return 0;
+}
+
+static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[EXPOSURE_IDX] = val;
        PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
 
        i2c_data = ((val & 0xff00) >> 8);
        PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
               i2c_data);
 
-       err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_H,
+       err = m5602_write_sensor(sd, PO1030_INTEGLINES_H,
                                  &i2c_data, 1);
        if (err < 0)
                return err;
@@ -233,167 +478,256 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        i2c_data = (val & 0xff);
        PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
               i2c_data);
-       err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_M,
+       err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,
                                  &i2c_data, 1);
 
        return err;
 }
 
-int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 i2c_data;
-       int err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
-                                &i2c_data, 1);
-       *val = i2c_data;
+       *val = sensor_settings[GAIN_IDX];
        PDEBUG(D_V4L2, "Read global gain %d", *val);
-
-       return err;
+       return 0;
 }
 
-int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       err = m5602_read_sensor(sd, PO1030_REG_CONTROL2,
+       sensor_settings[GAIN_IDX] = val;
+
+       i2c_data = val & 0xff;
+       PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
+       err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
                                 &i2c_data, 1);
+       return err;
+}
 
-       *val = (i2c_data >> 7) & 0x01 ;
+static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
+       *val = sensor_settings[HFLIP_IDX];
        PDEBUG(D_V4L2, "Read hflip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[HFLIP_IDX] = val;
+
        PDEBUG(D_V4L2, "Set hflip %d", val);
-       err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+       err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
        if (err < 0)
                return err;
 
        i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
 
-       err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+       err = m5602_write_sensor(sd, PO1030_CONTROL2,
                                 &i2c_data, 1);
 
        return err;
 }
 
-int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 i2c_data;
-       int err;
-
-       err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
-                                &i2c_data, 1);
-
-       *val = (i2c_data >> 6) & 0x01;
+       s32 *sensor_settings = sd->sensor_priv;
 
+       *val = sensor_settings[VFLIP_IDX];
        PDEBUG(D_V4L2, "Read vflip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[VFLIP_IDX] = val;
+
        PDEBUG(D_V4L2, "Set vflip %d", val);
-       err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+       err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
        if (err < 0)
                return err;
 
        i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
 
-       err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+       err = m5602_write_sensor(sd, PO1030_CONTROL2,
                                 &i2c_data, 1);
 
        return err;
 }
 
-int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[RED_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read red gain %d", *val);
+       return 0;
+}
+
+static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[RED_BALANCE_IDX] = val;
+
        i2c_data = val & 0xff;
-       PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
-       err = m5602_write_sensor(sd, PO1030_REG_GLOBALGAIN,
+       PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
+       err = m5602_write_sensor(sd, PO1030_RED_GAIN,
                                  &i2c_data, 1);
        return err;
 }
 
-int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 i2c_data;
-       int err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, PO1030_REG_RED_GAIN,
-                                &i2c_data, 1);
-       *val = i2c_data;
-       PDEBUG(D_V4L2, "Read red gain %d", *val);
-       return err;
+       *val = sensor_settings[BLUE_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read blue gain %d", *val);
+
+       return 0;
 }
 
-int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[BLUE_BALANCE_IDX] = val;
+
        i2c_data = val & 0xff;
-       PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
-       err = m5602_write_sensor(sd, PO1030_REG_RED_GAIN,
+       PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
+       err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
                                  &i2c_data, 1);
+
        return err;
 }
 
-int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GREEN_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read green gain %d", *val);
+
+       return 0;
+}
+
+static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       err = m5602_read_sensor(sd, PO1030_REG_BLUE_GAIN,
+       sensor_settings[GREEN_BALANCE_IDX] = val;
+       i2c_data = val & 0xff;
+       PDEBUG(D_V4L2, "Set green gain to %d", i2c_data);
+
+       err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
+                          &i2c_data, 1);
+       if (err < 0)
+               return err;
+
+       return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN,
                                 &i2c_data, 1);
-       *val = i2c_data;
-       PDEBUG(D_V4L2, "Read blue gain %d", *val);
+}
 
-       return err;
+static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Auto white balancing is %d", *val);
+
+       return 0;
 }
 
-int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
-       i2c_data = val & 0xff;
-       PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
-       err = m5602_write_sensor(sd, PO1030_REG_BLUE_GAIN,
-                                 &i2c_data, 1);
 
+       sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
+
+       err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
+       if (err < 0)
+               return err;
+
+       PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+       i2c_data = (i2c_data & 0xfe) | (val & 0x01);
+       err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
        return err;
 }
 
-int po1030_power_down(struct sd *sd)
+static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
+                                   __s32 *val)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[AUTO_EXPOSURE_IDX];
+       PDEBUG(D_V4L2, "Auto exposure is %d", *val);
        return 0;
 }
 
+static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
+                                   __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+       u8 i2c_data;
+       int err;
+
+       sensor_settings[AUTO_EXPOSURE_IDX] = val;
+       err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
+       if (err < 0)
+               return err;
+
+       PDEBUG(D_V4L2, "Set auto exposure to %d", val);
+       i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
+       return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
+}
+
+void po1030_disconnect(struct sd *sd)
+{
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
+}
+
 static void po1030_dump_registers(struct sd *sd)
 {
        int address;
index c10b12335818f1dc65fe53eda77545dda403f692..1ea380b2bbe73ee49c6734883a38a2d80b74d816 100644 (file)
 
 /*****************************************************************************/
 
-#define PO1030_REG_DEVID_H             0x00
-#define PO1030_REG_DEVID_L             0x01
-#define PO1030_REG_FRAMEWIDTH_H                0x04
-#define PO1030_REG_FRAMEWIDTH_L                0x05
-#define PO1030_REG_FRAMEHEIGHT_H       0x06
-#define PO1030_REG_FRAMEHEIGHT_L       0x07
-#define PO1030_REG_WINDOWX_H           0x08
-#define PO1030_REG_WINDOWX_L           0x09
-#define PO1030_REG_WINDOWY_H           0x0a
-#define PO1030_REG_WINDOWY_L           0x0b
-#define PO1030_REG_WINDOWWIDTH_H       0x0c
-#define PO1030_REG_WINDOWWIDTH_L       0x0d
-#define PO1030_REG_WINDOWHEIGHT_H      0x0e
-#define PO1030_REG_WINDOWHEIGHT_L      0x0f
-
-#define PO1030_REG_GLOBALIBIAS         0x12
-#define PO1030_REG_PIXELIBIAS          0x13
-
-#define PO1030_REG_GLOBALGAIN          0x15
-#define PO1030_REG_RED_GAIN            0x16
-#define PO1030_REG_GREEN_1_GAIN                0x17
-#define PO1030_REG_BLUE_GAIN           0x18
-#define PO1030_REG_GREEN_2_GAIN                0x19
-
-#define PO1030_REG_INTEGLINES_H                0x1a
-#define PO1030_REG_INTEGLINES_M                0x1b
-#define PO1030_REG_INTEGLINES_L                0x1c
-
-#define PO1030_REG_CONTROL1            0x1d
-#define PO1030_REG_CONTROL2            0x1e
-#define PO1030_REG_CONTROL3            0x1f
-#define PO1030_REG_CONTROL4            0x20
-
-#define PO1030_REG_PERIOD50_H          0x23
-#define PO1030_REG_PERIOD50_L          0x24
-#define PO1030_REG_PERIOD60_H          0x25
-#define PO1030_REG_PERIOD60_L          0x26
-#define PO1030_REG_REGCLK167           0x27
-#define PO1030_REG_DELTA50             0x28
-#define PO1030_REG_DELTA60             0x29
-
-#define PO1030_REG_ADCOFFSET           0x2c
+#define PO1030_DEVID_H         0x00
+#define PO1030_DEVID_L         0x01
+#define PO1030_FRAMEWIDTH_H    0x04
+#define PO1030_FRAMEWIDTH_L    0x05
+#define PO1030_FRAMEHEIGHT_H   0x06
+#define PO1030_FRAMEHEIGHT_L   0x07
+#define PO1030_WINDOWX_H       0x08
+#define PO1030_WINDOWX_L       0x09
+#define PO1030_WINDOWY_H       0x0a
+#define PO1030_WINDOWY_L       0x0b
+#define PO1030_WINDOWWIDTH_H   0x0c
+#define PO1030_WINDOWWIDTH_L   0x0d
+#define PO1030_WINDOWHEIGHT_H  0x0e
+#define PO1030_WINDOWHEIGHT_L  0x0f
+
+#define PO1030_GLOBALIBIAS     0x12
+#define PO1030_PIXELIBIAS      0x13
+
+#define PO1030_GLOBALGAIN      0x15
+#define PO1030_RED_GAIN                0x16
+#define PO1030_GREEN_1_GAIN    0x17
+#define PO1030_BLUE_GAIN       0x18
+#define PO1030_GREEN_2_GAIN    0x19
+
+#define PO1030_INTEGLINES_H    0x1a
+#define PO1030_INTEGLINES_M    0x1b
+#define PO1030_INTEGLINES_L    0x1c
+
+#define PO1030_CONTROL1                0x1d
+#define PO1030_CONTROL2                0x1e
+#define PO1030_CONTROL3                0x1f
+#define PO1030_CONTROL4                0x20
+
+#define PO1030_PERIOD50_H      0x23
+#define PO1030_PERIOD50_L      0x24
+#define PO1030_PERIOD60_H      0x25
+#define PO1030_PERIOD60_L      0x26
+#define PO1030_REGCLK167       0x27
+#define PO1030_FLICKER_DELTA50 0x28
+#define PO1030_FLICKERDELTA60  0x29
+
+#define PO1030_ADCOFFSET       0x2c
 
 /* Gamma Correction Coeffs */
-#define PO1030_REG_GC0                 0x2d
-#define PO1030_REG_GC1                 0x2e
-#define PO1030_REG_GC2                 0x2f
-#define PO1030_REG_GC3                 0x30
-#define PO1030_REG_GC4                 0x31
-#define PO1030_REG_GC5                 0x32
-#define PO1030_REG_GC6                 0x33
-#define PO1030_REG_GC7                 0x34
+#define PO1030_GC0             0x2d
+#define PO1030_GC1             0x2e
+#define PO1030_GC2             0x2f
+#define PO1030_GC3             0x30
+#define PO1030_GC4             0x31
+#define PO1030_GC5             0x32
+#define PO1030_GC6             0x33
+#define PO1030_GC7             0x34
 
 /* Color Transform Matrix */
-#define PO1030_REG_CT0                 0x35
-#define PO1030_REG_CT1                 0x36
-#define PO1030_REG_CT2                 0x37
-#define PO1030_REG_CT3                 0x38
-#define PO1030_REG_CT4                 0x39
-#define PO1030_REG_CT5                 0x3a
-#define PO1030_REG_CT6                 0x3b
-#define PO1030_REG_CT7                 0x3c
-#define PO1030_REG_CT8                 0x3d
-
-#define PO1030_REG_AUTOCTRL1           0x3e
-#define PO1030_REG_AUTOCTRL2           0x3f
-
-#define PO1030_REG_YTARGET             0x40
-#define PO1030_REG_GLOBALGAINMIN       0x41
-#define PO1030_REG_GLOBALGAINMAX       0x42
+#define PO1030_CT0             0x35
+#define PO1030_CT1             0x36
+#define PO1030_CT2             0x37
+#define PO1030_CT3             0x38
+#define PO1030_CT4             0x39
+#define PO1030_CT5             0x3a
+#define PO1030_CT6             0x3b
+#define PO1030_CT7             0x3c
+#define PO1030_CT8             0x3d
+
+#define PO1030_AUTOCTRL1       0x3e
+#define PO1030_AUTOCTRL2       0x3f
+
+#define PO1030_YTARGET         0x40
+#define PO1030_GLOBALGAINMIN   0x41
+#define PO1030_GLOBALGAINMAX   0x42
+
+#define PO1030_AWB_RED_TUNING  0x47
+#define PO1030_AWB_BLUE_TUNING 0x48
 
 /* Output format control */
-#define PO1030_REG_OUTFORMCTRL1                0x5a
-#define PO1030_REG_OUTFORMCTRL2                0x5b
-#define PO1030_REG_OUTFORMCTRL3                0x5c
-#define PO1030_REG_OUTFORMCTRL4                0x5d
-#define PO1030_REG_OUTFORMCTRL5                0x5e
+#define PO1030_OUTFORMCTRL1    0x5a
+#define PO1030_OUTFORMCTRL2    0x5b
+#define PO1030_OUTFORMCTRL3    0x5c
+#define PO1030_OUTFORMCTRL4    0x5d
+#define PO1030_OUTFORMCTRL5    0x5e
 
-/* Imaging coefficients */
-#define PO1030_REG_YBRIGHT             0x73
-#define PO1030_REG_YCONTRAST           0x74
-#define PO1030_REG_YSATURATION         0x75
+#define PO1030_EDGE_ENH_OFF    0x5f
+#define PO1030_EGA             0x60
 
-#define PO1030_HFLIP                   (1 << 7)
-#define PO1030_VFLIP                   (1 << 6)
+#define PO1030_Cb_U_GAIN       0x63
+#define PO1030_Cr_V_GAIN       0x64
+
+#define PO1030_YCONTRAST       0x74
+#define PO1030_YSATURATION     0x75
+
+#define PO1030_HFLIP           (1 << 7)
+#define PO1030_VFLIP           (1 << 6)
+
+#define PO1030_HREF_ENABLE     (1 << 6)
+
+#define PO1030_RAW_RGB_BAYER   0x4
+
+#define PO1030_FRAME_EQUAL     (1 << 3)
+#define PO1030_AUTO_SUBSAMPLING (1 << 4)
+
+#define PO1030_WEIGHT_WIN_2X   (1 << 3)
+
+#define PO1030_SHUTTER_MODE    (1 << 6)
+#define PO1030_AUTO_SUBSAMPLING        (1 << 4)
+#define PO1030_FRAME_EQUAL     (1 << 3)
+
+#define PO1030_SENSOR_RESET    (1 << 5)
+
+#define PO1030_SUBSAMPLING     (1 << 6)
 
 /*****************************************************************************/
 
 #define PO1030_GLOBAL_GAIN_DEFAULT     0x12
 #define PO1030_EXPOSURE_DEFAULT                0x0085
-#define PO1030_BLUE_GAIN_DEFAULT       0x40
-#define PO1030_RED_GAIN_DEFAULT        0x40
+#define PO1030_BLUE_GAIN_DEFAULT       0x36
+#define PO1030_RED_GAIN_DEFAULT        0x36
+#define PO1030_GREEN_GAIN_DEFAULT      0x40
 
 /*****************************************************************************/
 
@@ -126,20 +151,8 @@ extern int dump_sensor;
 
 int po1030_probe(struct sd *sd);
 int po1030_init(struct sd *sd);
-int po1030_power_down(struct sd *sd);
-
-int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_start(struct sd *sd);
+void po1030_disconnect(struct sd *sd);
 
 static const struct m5602_sensor po1030 = {
        .name = "PO1030",
@@ -149,7 +162,8 @@ static const struct m5602_sensor po1030 = {
 
        .probe = po1030_probe,
        .init = po1030_init,
-       .power_down = po1030_power_down,
+       .start = po1030_start,
+       .disconnect = po1030_disconnect,
 };
 
 static const unsigned char preinit_po1030[][3] =
@@ -159,248 +173,103 @@ static const unsigned char preinit_po1030[][3] =
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
        {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
-
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
-
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+
+       {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
+
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x00}
 };
 
-static const unsigned char init_po1030[][4] =
+static const unsigned char init_po1030[][3] =
 {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
-       /*sequence 1*/
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
-
        {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       /*end of sequence 1*/
-
-       /*sequence 2 (same as stop sequence)*/
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       /*end of sequence 2*/
 
-       /*sequence 5*/
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       /*end of sequence 5*/
-
-       /*sequence 2 stop */
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+       {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
 
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       /*end of sequence 2 stop */
-
-/* ---------------------------------
- * end of init - begin of start
- * --------------------------------- */
-
-       /*sequence 3*/
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       /*end of sequence 3*/
-       /*sequence 4*/
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
 
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x04},
+       {SENSOR, PO1030_AUTOCTRL2, 0x04},
+
+       {SENSOR, PO1030_OUTFORMCTRL2, PO1030_RAW_RGB_BAYER},
+       {SENSOR, PO1030_AUTOCTRL1, PO1030_WEIGHT_WIN_2X},
+
+       {SENSOR, PO1030_CONTROL2, 0x03},
+       {SENSOR, 0x21, 0x90},
+       {SENSOR, PO1030_YTARGET, 0x60},
+       {SENSOR, 0x59, 0x13},
+       {SENSOR, PO1030_OUTFORMCTRL1, PO1030_HREF_ENABLE},
+       {SENSOR, PO1030_EDGE_ENH_OFF, 0x00},
+       {SENSOR, PO1030_EGA, 0x80},
+       {SENSOR, 0x78, 0x14},
+       {SENSOR, 0x6f, 0x01},
+       {SENSOR, PO1030_GLOBALGAINMAX, 0x14},
+       {SENSOR, PO1030_Cb_U_GAIN, 0x38},
+       {SENSOR, PO1030_Cr_V_GAIN, 0x38},
+       {SENSOR, PO1030_CONTROL1, PO1030_SHUTTER_MODE |
+                                 PO1030_AUTO_SUBSAMPLING |
+                                 PO1030_FRAME_EQUAL},
+       {SENSOR, PO1030_GC0, 0x10},
+       {SENSOR, PO1030_GC1, 0x20},
+       {SENSOR, PO1030_GC2, 0x40},
+       {SENSOR, PO1030_GC3, 0x60},
+       {SENSOR, PO1030_GC4, 0x80},
+       {SENSOR, PO1030_GC5, 0xa0},
+       {SENSOR, PO1030_GC6, 0xc0},
+       {SENSOR, PO1030_GC7, 0xff},
 
        /* Set the width to 751 */
-       {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
-       {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef},
+       {SENSOR, PO1030_FRAMEWIDTH_H, 0x02},
+       {SENSOR, PO1030_FRAMEWIDTH_L, 0xef},
 
        /* Set the height to 540 */
-       {SENSOR, PO1030_REG_FRAMEHEIGHT_H, 0x02},
-       {SENSOR, PO1030_REG_FRAMEHEIGHT_L, 0x1c},
+       {SENSOR, PO1030_FRAMEHEIGHT_H, 0x02},
+       {SENSOR, PO1030_FRAMEHEIGHT_L, 0x1c},
 
        /* Set the x window to 1 */
-       {SENSOR, PO1030_REG_WINDOWX_H, 0x00},
-       {SENSOR, PO1030_REG_WINDOWX_L, 0x01},
+       {SENSOR, PO1030_WINDOWX_H, 0x00},
+       {SENSOR, PO1030_WINDOWX_L, 0x01},
 
        /* Set the y window to 1 */
-       {SENSOR, PO1030_REG_WINDOWY_H, 0x00},
-       {SENSOR, PO1030_REG_WINDOWY_L, 0x01},
-
-       {SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02},
-       {SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87},
-       {SENSOR, PO1030_REG_WINDOWHEIGHT_H, 0x01},
-       {SENSOR, PO1030_REG_WINDOWHEIGHT_L, 0xe3},
-
-       {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
-       {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
-       {SENSOR, PO1030_REG_AUTOCTRL1, 0x08},
-       {SENSOR, PO1030_REG_CONTROL2, 0x03},
-       {SENSOR, 0x21, 0x90},
-       {SENSOR, PO1030_REG_YTARGET, 0x60},
-       {SENSOR, 0x59, 0x13},
-       {SENSOR, PO1030_REG_OUTFORMCTRL1, 0x40},
-       {SENSOR, 0x5f, 0x00},
-       {SENSOR, 0x60, 0x80},
-       {SENSOR, 0x78, 0x14},
-       {SENSOR, 0x6f, 0x01},
-       {SENSOR, PO1030_REG_CONTROL1, 0x18},
-       {SENSOR, PO1030_REG_GLOBALGAINMAX, 0x14},
-       {SENSOR, 0x63, 0x38},
-       {SENSOR, 0x64, 0x38},
-       {SENSOR, PO1030_REG_CONTROL1, 0x58},
-       {SENSOR, PO1030_REG_RED_GAIN, 0x30},
-       {SENSOR, PO1030_REG_GREEN_1_GAIN, 0x30},
-       {SENSOR, PO1030_REG_BLUE_GAIN, 0x30},
-       {SENSOR, PO1030_REG_GREEN_2_GAIN, 0x30},
-       {SENSOR, PO1030_REG_GC0, 0x10},
-       {SENSOR, PO1030_REG_GC1, 0x20},
-       {SENSOR, PO1030_REG_GC2, 0x40},
-       {SENSOR, PO1030_REG_GC3, 0x60},
-       {SENSOR, PO1030_REG_GC4, 0x80},
-       {SENSOR, PO1030_REG_GC5, 0xa0},
-       {SENSOR, PO1030_REG_GC6, 0xc0},
-       {SENSOR, PO1030_REG_GC7, 0xff},
-       /*end of sequence 4*/
-       /*sequence 5*/
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7e},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       /*end of sequence 5*/
-
-       /*sequence 6*/
-       /* Changing 40 in f0 the image becomes green in bayer mode and red in
-        * rgb mode */
-       {SENSOR, PO1030_REG_RED_GAIN, PO1030_RED_GAIN_DEFAULT},
-       /* in changing 40 in f0 the image becomes green in bayer mode and red in
-        * rgb mode */
-       {SENSOR, PO1030_REG_BLUE_GAIN, PO1030_BLUE_GAIN_DEFAULT},
+       {SENSOR, PO1030_WINDOWY_H, 0x00},
+       {SENSOR, PO1030_WINDOWY_L, 0x01},
 
        /* with a very low lighted environment increase the exposure but
         * decrease the FPS (Frame Per Second) */
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
 
-       /* Controls high exposure more than SENSOR_LOW_EXPOSURE, use only in
-        * low lighted environment (f0 is more than ff ?)*/
-       {SENSOR, PO1030_REG_INTEGLINES_H, ((PO1030_EXPOSURE_DEFAULT >> 2)
-               & 0xff)},
-
-       /* Controls middle exposure, use only in high lighted environment */
-       {SENSOR, PO1030_REG_INTEGLINES_M, PO1030_EXPOSURE_DEFAULT & 0xff},
-
-       /* Controls clarity (not sure) */
-       {SENSOR, PO1030_REG_INTEGLINES_L, 0x00},
-       /* Controls gain (the image is more lighted) */
-       {SENSOR, PO1030_REG_GLOBALGAIN, PO1030_GLOBAL_GAIN_DEFAULT},
-
-       /* Sets the width */
-       {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
-       {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef}
-       /*end of sequence 6*/
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
 };
 
 #endif
index 4306d596056db72a66587a8da4ad25a22b35d46a..191bcd7189798351e5a171767c86fd5e7b8686b1 100644 (file)
 
 #include "m5602_s5k4aa.h"
 
+static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+
 static
     const
        struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
@@ -46,6 +59,18 @@ static
                        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
                }
+       }, {
+               .ident = "MSI L735",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
+               }
+       }, {
+               .ident = "Lenovo Y300",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
+               }
        },
        { }
 };
@@ -61,10 +86,22 @@ static struct v4l2_pix_format s5k4aa_modes[] = {
                .bytesperline = 640,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0
+       },
+       {
+               1280,
+               1024,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       1280 * 1024,
+               .bytesperline = 1280,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
        }
 };
 
-const static struct ctrl s5k4aa_ctrls[] = {
+static const struct ctrl s5k4aa_ctrls[] = {
+#define VFLIP_IDX 0
        {
                {
                        .id             = V4L2_CID_VFLIP,
@@ -77,8 +114,9 @@ const static struct ctrl s5k4aa_ctrls[] = {
                },
                .set = s5k4aa_set_vflip,
                .get = s5k4aa_get_vflip
-
-       }, {
+       },
+#define HFLIP_IDX 1
+       {
                {
                        .id             = V4L2_CID_HFLIP,
                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -90,8 +128,9 @@ const static struct ctrl s5k4aa_ctrls[] = {
                },
                .set = s5k4aa_set_hflip,
                .get = s5k4aa_get_hflip
-
-       }, {
+       },
+#define GAIN_IDX 2
+       {
                {
                        .id             = V4L2_CID_GAIN,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -99,12 +138,14 @@ const static struct ctrl s5k4aa_ctrls[] = {
                        .minimum        = 0,
                        .maximum        = 127,
                        .step           = 1,
-                       .default_value  = 0xa0,
+                       .default_value  = S5K4AA_DEFAULT_GAIN,
                        .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = s5k4aa_set_gain,
                .get = s5k4aa_get_gain
-       }, {
+       },
+#define EXPOSURE_IDX 3
+       {
                {
                        .id             = V4L2_CID_EXPOSURE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -117,7 +158,36 @@ const static struct ctrl s5k4aa_ctrls[] = {
                },
                .set = s5k4aa_set_exposure,
                .get = s5k4aa_get_exposure
-       }
+       },
+#define NOISE_SUPP_IDX 4
+       {
+               {
+                       .id             = V4L2_CID_PRIVATE_BASE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "Noise suppression (smoothing)",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1,
+               },
+                       .set = s5k4aa_set_noise,
+                       .get = s5k4aa_get_noise
+       },
+#define BRIGHTNESS_IDX 5
+       {
+               {
+                       .id             = V4L2_CID_BRIGHTNESS,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Brightness",
+                       .minimum        = 0,
+                       .maximum        = 0x1f,
+                       .step           = 1,
+                       .default_value  = S5K4AA_DEFAULT_BRIGHTNESS,
+               },
+                       .set = s5k4aa_set_brightness,
+                       .get = s5k4aa_get_brightness
+       },
+
 };
 
 static void s5k4aa_dump_registers(struct sd *sd);
@@ -127,6 +197,7 @@ int s5k4aa_probe(struct sd *sd)
        u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
        const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
        int i, err = 0;
+       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == S5K4AA_SENSOR) {
@@ -185,10 +256,20 @@ int s5k4aa_probe(struct sd *sd)
                info("Detected a s5k4aa sensor");
 
 sensor_found:
+       sensor_settings = kmalloc(
+               ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
+       if (!sensor_settings)
+               return -ENOMEM;
+
        sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
        sd->desc->ctrls = s5k4aa_ctrls;
        sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
+
+       for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
+               sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
+       sd->sensor_priv = sensor_settings;
+
        return 0;
 }
 
@@ -197,9 +278,45 @@ int s5k4aa_start(struct sd *sd)
        int i, err = 0;
        u8 data[2];
        struct cam *cam = &sd->gspca_dev.cam;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
+       case 1280:
+               PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
+
+               for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
+                       switch (SXGA_s5k4aa[i][0]) {
+                       case BRIDGE:
+                               err = m5602_write_bridge(sd,
+                                                SXGA_s5k4aa[i][1],
+                                                SXGA_s5k4aa[i][2]);
+                       break;
+
+                       case SENSOR:
+                               data[0] = SXGA_s5k4aa[i][2];
+                               err = m5602_write_sensor(sd,
+                                                SXGA_s5k4aa[i][1],
+                                                data, 1);
+                       break;
+
+                       case SENSOR_LONG:
+                               data[0] = SXGA_s5k4aa[i][2];
+                               data[1] = SXGA_s5k4aa[i][3];
+                               err = m5602_write_sensor(sd,
+                                                 SXGA_s5k4aa[i][1],
+                                                 data, 2);
+                       break;
+
+                       default:
+                               err("Invalid stream command, exiting init");
+                               return -EINVAL;
+                       }
+               }
+               err = s5k4aa_set_noise(&sd->gspca_dev, 0);
+               if (err < 0)
+                       return err;
+               break;
 
-       switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
-       {
        case 640:
                PDEBUG(D_V4L2, "Configuring camera for VGA mode");
 
@@ -231,8 +348,37 @@ int s5k4aa_start(struct sd *sd)
                                return -EINVAL;
                        }
                }
+               err = s5k4aa_set_noise(&sd->gspca_dev, 1);
+               if (err < 0)
+                       return err;
+               break;
        }
-       return err;
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_brightness(&sd->gspca_dev,
+                                    sensor_settings[BRIGHTNESS_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
 }
 
 int s5k4aa_init(struct sd *sd)
@@ -270,62 +416,28 @@ int s5k4aa_init(struct sd *sd)
        if (dump_sensor)
                s5k4aa_dump_registers(sd);
 
-       if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
-               u8 data = 0x02;
-               info("vertical flip quirk active");
-               m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-               m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
-               data |= S5K4AA_RM_V_FLIP;
-               data &= ~S5K4AA_RM_H_FLIP;
-               m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
-
-               /* Decrement COLSTART to preserve color order (BGGR) */
-               m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-               data--;
-               m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-
-               /* Increment ROWSTART to preserve color order (BGGR) */
-               m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-               data++;
-               m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-       }
-
-       return (err < 0) ? err : 0;
-}
-
-int s5k4aa_power_down(struct sd *sd)
-{
-       return 0;
+       return err;
 }
 
-int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 data = S5K4AA_PAGE_MAP_2;
-       int err;
-
-       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       if (err < 0)
-               return err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
-       if (err < 0)
-               return err;
-
-       *val = data << 8;
-       err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
-       *val |= data;
+       *val = sensor_settings[EXPOSURE_IDX];
        PDEBUG(D_V4L2, "Read exposure %d", *val);
 
-       return err;
+       return 0;
 }
 
-int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
+       sensor_settings[EXPOSURE_IDX] = val;
        PDEBUG(D_V4L2, "Set exposure to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
@@ -340,29 +452,26 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 data = S5K4AA_PAGE_MAP_2;
-       int err;
-
-       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       if (err < 0)
-               return err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       *val = (data & S5K4AA_RM_V_FLIP) >> 7;
+       *val = sensor_settings[VFLIP_IDX];
        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
+       sensor_settings[VFLIP_IDX] = val;
+
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
@@ -370,56 +479,48 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                return err;
-       data = ((data & ~S5K4AA_RM_V_FLIP)
-                       | ((val & 0x01) << 7));
-       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+
+       err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                return err;
 
-       if (val) {
-               err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
-
-               data++;
-               err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-       } else {
-               err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
+       if (dmi_check_system(s5k4aa_vflip_dmi_table))
+               val = !val;
 
-               data--;
-               err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-       }
+       data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
+       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       if (err < 0)
+               return err;
 
+       err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+       if (err < 0)
+               return err;
+       data = (data & 0xfe) | !val;
+       err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
        return err;
 }
 
-int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 data = S5K4AA_PAGE_MAP_2;
-       int err;
-
-       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       if (err < 0)
-               return err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       *val = (data & S5K4AA_RM_H_FLIP) >> 6;
+       *val = sensor_settings[HFLIP_IDX];
        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       PDEBUG(D_V4L2, "Set horizontal flip to %d",
-              val);
+       sensor_settings[HFLIP_IDX] = val;
+
+       PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                return err;
@@ -427,62 +528,116 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        if (err < 0)
                return err;
 
+       err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       if (err < 0)
+               return err;
+
+       if (dmi_check_system(s5k4aa_vflip_dmi_table))
+               val = !val;
+
        data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
        err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                return err;
 
-       if (val) {
-               err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
-               data++;
-               err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
-       } else {
-               err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
-               data--;
-               err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-       }
-
+       err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+       if (err < 0)
+               return err;
+       data = (data & 0xfe) | !val;
+       err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
        return err;
 }
 
-int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GAIN_IDX];
+       PDEBUG(D_V4L2, "Read gain %d", *val);
+       return 0;
+}
+
+static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
+       sensor_settings[GAIN_IDX] = val;
+
+       PDEBUG(D_V4L2, "Set gain to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                return err;
 
-       err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
-       *val = data;
-       PDEBUG(D_V4L2, "Read gain %d", *val);
+       data = val & 0xff;
+       err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
 
        return err;
 }
 
-int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[BRIGHTNESS_IDX];
+       PDEBUG(D_V4L2, "Read brightness %d", *val);
+       return 0;
+}
+
+static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       PDEBUG(D_V4L2, "Set gain to %d", val);
+       sensor_settings[BRIGHTNESS_IDX] = val;
+
+       PDEBUG(D_V4L2, "Set brightness to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                return err;
 
        data = val & 0xff;
-       err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+       return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
+}
 
-       return err;
+static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[NOISE_SUPP_IDX];
+       PDEBUG(D_V4L2, "Read noise %d", *val);
+       return 0;
+}
+
+static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       sensor_settings[NOISE_SUPP_IDX] = val;
+
+       PDEBUG(D_V4L2, "Set noise to %d", val);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               return err;
+
+       data = val & 0x01;
+       return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
+}
+
+void s5k4aa_disconnect(struct sd *sd)
+{
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
 }
 
 static void s5k4aa_dump_registers(struct sd *sd)
index ca854d4f9475e94ddce7ea164870133632db8792..4440da4e7f0ff3595fde22eabf7b3e4add002fd9 100644 (file)
@@ -47,8 +47,9 @@
 #define S5K4AA_H_BLANK_LO__            0x1e
 #define S5K4AA_EXPOSURE_HI             0x17
 #define S5K4AA_EXPOSURE_LO             0x18
-#define S5K4AA_GAIN_1                  0x1f /* (digital?) gain : 5 bits */
-#define S5K4AA_GAIN_2                  0x20 /* (analogue?) gain : 7 bits */
+#define S5K4AA_BRIGHTNESS              0x1f /* (digital?) gain : 5 bits */
+#define S5K4AA_GAIN                    0x20 /* (analogue?) gain : 7 bits */
+#define S5K4AA_NOISE_SUPP              0x37
 
 #define S5K4AA_RM_ROW_SKIP_4X          0x08
 #define S5K4AA_RM_ROW_SKIP_2X          0x04
@@ -57,6 +58,9 @@
 #define S5K4AA_RM_H_FLIP               0x40
 #define S5K4AA_RM_V_FLIP               0x80
 
+#define S5K4AA_DEFAULT_GAIN            0x5f
+#define S5K4AA_DEFAULT_BRIGHTNESS      0x10
+
 /*****************************************************************************/
 
 /* Kernel module parameters */
@@ -66,25 +70,17 @@ extern int dump_sensor;
 int s5k4aa_probe(struct sd *sd);
 int s5k4aa_init(struct sd *sd);
 int s5k4aa_start(struct sd *sd);
-int s5k4aa_power_down(struct sd *sd);
-
-int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+void s5k4aa_disconnect(struct sd *sd);
 
 static const struct m5602_sensor s5k4aa = {
        .name = "S5K4AA",
+       .i2c_slave_id = 0x5a,
+       .i2c_regW = 2,
+
        .probe = s5k4aa_probe,
        .init = s5k4aa_init,
        .start = s5k4aa_start,
-       .power_down = s5k4aa_power_down,
-       .i2c_slave_id = 0x5a,
-       .i2c_regW = 2,
+       .disconnect = s5k4aa_disconnect,
 };
 
 static const unsigned char preinit_s5k4aa[][4] =
@@ -179,30 +175,12 @@ static const unsigned char init_s5k4aa[][4] =
        {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
        {SENSOR, 0x0c, 0x05, 0x00},
        {SENSOR, 0x02, 0x0e, 0x00},
-       {SENSOR, S5K4AA_GAIN_1, 0x0f, 0x00},
-       {SENSOR, S5K4AA_GAIN_2, 0x00, 0x00},
-       {SENSOR, S5K4AA_GLOBAL_GAIN__, 0x01, 0x00},
-       {SENSOR, 0x11, 0x00, 0x00},
-       {SENSOR, 0x12, 0x00, 0x00},
-       {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
        {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00},
        {SENSOR, 0x37, 0x00, 0x00},
-       {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
-       {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_COLSTART_LO, 0x0b, 0x00},
-       {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
-       {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc4, 0x00},
-       {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
-       {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x08, 0x00},
-       {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
-       {SENSOR, S5K4AA_H_BLANK_LO__, 0x48, 0x00},
-       {SENSOR, S5K4AA_EXPOSURE_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_EXPOSURE_LO, 0x43, 0x00},
-       {SENSOR, 0x11, 0x04, 0x00},
-       {SENSOR, 0x12, 0xc3, 0x00},
-       {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+};
 
+static const unsigned char VGA_s5k4aa[][4] =
+{
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -238,7 +216,7 @@ static const unsigned char init_s5k4aa[][4] =
        {SENSOR, 0x37, 0x01, 0x00},
        /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
        {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+       {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00},
        {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
        {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
        /* window_height_hi, window_height_lo : 960 = 0x03c0 */
@@ -255,12 +233,9 @@ static const unsigned char init_s5k4aa[][4] =
        {SENSOR, 0x12, 0xc3, 0x00},
        {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
        {SENSOR, 0x02, 0x0e, 0x00},
-       {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00},
-       {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00},
-       {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
 };
 
-static const unsigned char VGA_s5k4aa[][4] =
+static const unsigned char SXGA_s5k4aa[][4] =
 {
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
@@ -273,50 +248,42 @@ static const unsigned char VGA_s5k4aa[][4] =
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
+       /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00},
+       /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
 
        {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
-       {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X
-               | S5K4AA_RM_COL_SKIP_2X, 0x00},
-       /* 0x37 : Fix image stability when light is too bright and improves
-        * image quality in 640x480, but worsens it in 1280x1024 */
+       {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00},
        {SENSOR, 0x37, 0x01, 0x00},
-       /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
        {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+       {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00},
        {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
-       /* window_height_hi, window_height_lo : 960 = 0x03c0 */
-       {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
-       {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00},
-       /* window_width_hi, window_width_lo : 1280 = 0x0500 */
+       {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00},
+       {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00},
+       {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00},
        {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
        {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
-       {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
-       {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */
+       {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00},
+       {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00},
        {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
        {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
        {SENSOR, 0x11, 0x04, 0x00},
        {SENSOR, 0x12, 0xc3, 0x00},
        {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
        {SENSOR, 0x02, 0x0e, 0x00},
-       {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00},
-       {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00},
-       {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
 };
 
+
 #endif
index 42c86aa4dc8d073ca9931a6b256101f0dbcc85c8..7127321ace8cbe35e893dd40025bbb901e60ee51 100644 (file)
  *
  */
 
+#include <linux/kthread.h>
 #include "m5602_s5k83a.h"
 
+static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+
 static struct v4l2_pix_format s5k83a_modes[] = {
        {
                640,
@@ -32,68 +44,77 @@ static struct v4l2_pix_format s5k83a_modes[] = {
        }
 };
 
-const static struct ctrl s5k83a_ctrls[] = {
+static const struct ctrl s5k83a_ctrls[] = {
+#define GAIN_IDX 0
        {
                {
-                       .id = V4L2_CID_BRIGHTNESS,
+                       .id = V4L2_CID_GAIN,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "brightness",
+                       .name = "gain",
                        .minimum = 0x00,
                        .maximum = 0xff,
                        .step = 0x01,
-                       .default_value = S5K83A_DEFAULT_BRIGHTNESS,
+                       .default_value = S5K83A_DEFAULT_GAIN,
                        .flags = V4L2_CTRL_FLAG_SLIDER
                },
-                       .set = s5k83a_set_brightness,
-                       .get = s5k83a_get_brightness
+                       .set = s5k83a_set_gain,
+                       .get = s5k83a_get_gain
 
-       }, {
+       },
+#define BRIGHTNESS_IDX 1
+       {
                {
-                       .id = V4L2_CID_WHITENESS,
+                       .id = V4L2_CID_BRIGHTNESS,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "whiteness",
+                       .name = "brightness",
                        .minimum = 0x00,
                        .maximum = 0xff,
                        .step = 0x01,
-                       .default_value = S5K83A_DEFAULT_WHITENESS,
+                       .default_value = S5K83A_DEFAULT_BRIGHTNESS,
                        .flags = V4L2_CTRL_FLAG_SLIDER
                },
-                       .set = s5k83a_set_whiteness,
-                       .get = s5k83a_get_whiteness,
-       }, {
+                       .set = s5k83a_set_brightness,
+                       .get = s5k83a_get_brightness,
+       },
+#define EXPOSURE_IDX 2
+       {
                {
-                       .id = V4L2_CID_GAIN,
+                       .id = V4L2_CID_EXPOSURE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "gain",
+                       .name = "exposure",
                        .minimum = 0x00,
-                       .maximum = S5K83A_MAXIMUM_GAIN,
+                       .maximum = S5K83A_MAXIMUM_EXPOSURE,
                        .step = 0x01,
-                       .default_value = S5K83A_DEFAULT_GAIN,
+                       .default_value = S5K83A_DEFAULT_EXPOSURE,
                        .flags = V4L2_CTRL_FLAG_SLIDER
                },
-                       .set = s5k83a_set_gain,
-                       .get = s5k83a_get_gain
-       }, {
+                       .set = s5k83a_set_exposure,
+                       .get = s5k83a_get_exposure
+       },
+#define HFLIP_IDX 3
+       {
                {
-                       .id         = V4L2_CID_HFLIP,
-                       .type       = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name       = "horizontal flip",
-                       .minimum    = 0,
-                       .maximum    = 1,
-                       .step       = 1,
-                       .default_value  = 0
+                       .id = V4L2_CID_HFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "horizontal flip",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 1,
+                       .default_value = 0
                },
                        .set = s5k83a_set_hflip,
                        .get = s5k83a_get_hflip
-       }, {
+       },
+#define VFLIP_IDX 4
+       {
                {
-                .id         = V4L2_CID_VFLIP,
-               .type       = V4L2_CTRL_TYPE_BOOLEAN,
-               .name       = "vertical flip",
-               .minimum    = 0,
-               .maximum    = 1,
-               .step       = 1,
-               .default_value  = 0
+                       .id = V4L2_CID_VFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "vertical flip",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 1,
+                       .default_value = 0
                },
                .set = s5k83a_set_vflip,
                .get = s5k83a_get_vflip
@@ -101,9 +122,14 @@ const static struct ctrl s5k83a_ctrls[] = {
 };
 
 static void s5k83a_dump_registers(struct sd *sd);
+static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
+static int s5k83a_set_led_indication(struct sd *sd, u8 val);
+static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
+                               __s32 vflip, __s32 hflip);
 
 int s5k83a_probe(struct sd *sd)
 {
+       struct s5k83a_priv *sens_priv;
        u8 prod_id = 0, ver_id = 0;
        int i, err = 0;
 
@@ -145,16 +171,36 @@ int s5k83a_probe(struct sd *sd)
                info("Detected a s5k83a sensor");
 
 sensor_found:
+       sens_priv = kmalloc(
+               sizeof(struct s5k83a_priv), GFP_KERNEL);
+       if (!sens_priv)
+               return -ENOMEM;
+
+       sens_priv->settings =
+       kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
+       if (!sens_priv->settings)
+               return -ENOMEM;
+
        sd->gspca_dev.cam.cam_mode = s5k83a_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
        sd->desc->ctrls = s5k83a_ctrls;
        sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
+
+       /* null the pointer! thread is't running now */
+       sens_priv->rotation_thread = NULL;
+
+       for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
+               sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
+
+       sd->sensor_priv = sens_priv;
        return 0;
 }
 
 int s5k83a_init(struct sd *sd)
 {
        int i, err = 0;
+       s32 *sensor_settings =
+                       ((struct s5k83a_priv *) sd->sensor_priv)->settings;
 
        for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
                u8 data[2] = {0x00, 0x00};
@@ -187,87 +233,138 @@ int s5k83a_init(struct sd *sd)
        if (dump_sensor)
                s5k83a_dump_registers(sd);
 
-       return (err < 0) ? err : 0;
-}
+       err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       if (err < 0)
+               return err;
 
-int s5k83a_start(struct sd *sd)
-{
-       return s5k83a_set_led_indication(sd, 1);
-}
+       err = s5k83a_set_brightness(&sd->gspca_dev,
+                                    sensor_settings[BRIGHTNESS_IDX]);
+       if (err < 0)
+               return err;
 
-int s5k83a_stop(struct sd *sd)
-{
-       return s5k83a_set_led_indication(sd, 0);
+       err = s5k83a_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+
+       return err;
 }
 
-int s5k83a_power_down(struct sd *sd)
+static int rotation_thread_function(void *data)
 {
+       struct sd *sd = (struct sd *) data;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
+       u8 reg, previous_rotation = 0;
+       __s32 vflip, hflip;
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       while (!schedule_timeout(100)) {
+               if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
+                       break;
+
+               s5k83a_get_rotation(sd, &reg);
+               if (previous_rotation != reg) {
+                       previous_rotation = reg;
+                       info("Camera was flipped");
+
+                       s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
+                       s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+
+                       if (reg) {
+                               vflip = !vflip;
+                               hflip = !hflip;
+                       }
+                       s5k83a_set_flip_real((struct gspca_dev *) sd,
+                                             vflip, hflip);
+               }
+
+               mutex_unlock(&sd->gspca_dev.usb_lock);
+               set_current_state(TASK_INTERRUPTIBLE);
+       }
+
+       /* return to "front" flip */
+       if (previous_rotation) {
+               s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
+               s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+               s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
+       }
+
+       sens_priv->rotation_thread = NULL;
        return 0;
 }
 
-static void s5k83a_dump_registers(struct sd *sd)
+int s5k83a_start(struct sd *sd)
 {
-       int address;
-       u8 page, old_page;
-       m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+       int i, err = 0;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       for (page = 0; page < 16; page++) {
-               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
-               info("Dumping the s5k83a register state for page 0x%x", page);
-               for (address = 0; address <= 0xff; address++) {
-                       u8 val = 0;
-                       m5602_read_sensor(sd, address, &val, 1);
-                       info("register 0x%x contains 0x%x",
-                            address, val);
-               }
+       /* Create another thread, polling the GPIO ports of the camera to check
+          if it got rotated. This is how the windows driver does it so we have
+          to assume that there is no better way of accomplishing this */
+       sens_priv->rotation_thread = kthread_create(rotation_thread_function,
+                                                   sd, "rotation thread");
+       wake_up_process(sens_priv->rotation_thread);
+
+       /* Preinit the sensor */
+       for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
+               u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
+               if (start_s5k83a[i][0] == SENSOR)
+                       err = m5602_write_sensor(sd, start_s5k83a[i][1],
+                               data, 2);
+               else
+                       err = m5602_write_bridge(sd, start_s5k83a[i][1],
+                               data[0]);
        }
-       info("s5k83a register state dump complete");
+       if (err < 0)
+               return err;
 
-       for (page = 0; page < 16; page++) {
-               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
-               info("Probing for which registers that are read/write "
-                     "for page 0x%x", page);
-               for (address = 0; address <= 0xff; address++) {
-                       u8 old_val, ctrl_val, test_val = 0xff;
+       return s5k83a_set_led_indication(sd, 1);
+}
 
-                       m5602_read_sensor(sd, address, &old_val, 1);
-                       m5602_write_sensor(sd, address, &test_val, 1);
-                       m5602_read_sensor(sd, address, &ctrl_val, 1);
+int s5k83a_stop(struct sd *sd)
+{
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-                       if (ctrl_val == test_val)
-                               info("register 0x%x is writeable", address);
-                       else
-                               info("register 0x%x is read only", address);
+       if (sens_priv->rotation_thread)
+               kthread_stop(sens_priv->rotation_thread);
 
-                       /* Restore original val */
-                       m5602_write_sensor(sd, address, &old_val, 1);
-               }
-       }
-       info("Read/write register probing complete");
-       m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+       return s5k83a_set_led_indication(sd, 0);
 }
 
-int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+void s5k83a_disconnect(struct sd *sd)
 {
-       int err;
-       u8 data[2];
-       struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
-       if (err < 0)
-               return err;
+       s5k83a_stop(sd);
+
+       sd->sensor = NULL;
+       kfree(sens_priv->settings);
+       kfree(sens_priv);
+}
 
-       data[1] = data[1] << 1;
-       *val = data[1];
+static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       return err;
+       *val = sens_priv->settings[GAIN_IDX];
+       return 0;
 }
 
-int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
+
+       sens_priv->settings[GAIN_IDX] = val;
 
        data[0] = 0x00;
        data[1] = 0x20;
@@ -283,89 +380,69 @@ int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 
        /* FIXME: This is not sane, we need to figure out the composition
                  of these registers */
-       data[0] = val >> 3; /* brightness, high 5 bits */
-       data[1] = val >> 1; /* brightness, high 7 bits */
-       err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+       data[0] = val >> 3; /* gain, high 5 bits */
+       data[1] = val >> 1; /* gain, high 7 bits */
+       err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
 
        return err;
 }
 
-int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data;
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
-       if (err < 0)
-               return err;
-
-       *val = data;
-
-       return err;
+       *val = sens_priv->settings[BRIGHTNESS_IDX];
+       return 0;
 }
 
-int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[1];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
+       sens_priv->settings[BRIGHTNESS_IDX] = val;
        data[0] = val;
-       err = m5602_write_sensor(sd, S5K83A_WHITENESS, data, 1);
-
+       err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
        return err;
 }
 
-int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K83A_GAIN, data, 2);
-       if (err < 0)
-               return err;
-
-       data[1] = data[1] & 0x3f;
-       if (data[1] > S5K83A_MAXIMUM_GAIN)
-               data[1] = S5K83A_MAXIMUM_GAIN;
-
-       *val = data[1];
-
-       return err;
+       *val = sens_priv->settings[EXPOSURE_IDX];
+       return 0;
 }
 
-int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
+       sens_priv->settings[EXPOSURE_IDX] = val;
        data[0] = 0;
        data[1] = val;
-       err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
+       err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
        return err;
 }
 
-int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data[1];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       data[0] = 0x05;
-       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
-       if (err < 0)
-               return err;
-
-       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
-       *val = (data[0] | 0x40) ? 1 : 0;
-
-       return err;
+       *val = sens_priv->settings[VFLIP_IDX];
+       return 0;
 }
 
-int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
+                               __s32 vflip, __s32 hflip)
 {
        int err;
        u8 data[1];
@@ -376,69 +453,83 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        if (err < 0)
                return err;
 
-       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
-       if (err < 0)
-               return err;
+       /* six bit is vflip, seven is hflip */
+       data[0] = S5K83A_FLIP_MASK;
+       data[0] = (vflip) ? data[0] | 0x40 : data[0];
+       data[0] = (hflip) ? data[0] | 0x80 : data[0];
 
-       /* set or zero six bit, seven is hflip */
-       data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK
-                       : (data[0] & 0x80) | S5K83A_FLIP_MASK;
        err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
        if (err < 0)
                return err;
 
-       data[0] = (val) ? 0x0b : 0x0a;
+       data[0] = (vflip) ? 0x0b : 0x0a;
        err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
+       if (err < 0)
+               return err;
 
+       data[0] = (hflip) ? 0x0a : 0x0b;
+       err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
        return err;
 }
 
-int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
-       u8 data[1];
+       u8 reg;
+       __s32 hflip;
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       data[0] = 0x05;
-       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       sens_priv->settings[VFLIP_IDX] = val;
+
+       s5k83a_get_hflip(gspca_dev, &hflip);
+
+       err = s5k83a_get_rotation(sd, &reg);
        if (err < 0)
                return err;
+       if (reg) {
+               val = !val;
+               hflip = !hflip;
+       }
 
-       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
-       *val = (data[0] | 0x80) ? 1 : 0;
-
+       err = s5k83a_set_flip_real(gspca_dev, val, hflip);
        return err;
 }
 
-int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
+
+       *val = sens_priv->settings[HFLIP_IDX];
+       return 0;
+}
+
+static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
-       u8 data[1];
+       u8 reg;
+       __s32 vflip;
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       data[0] = 0x05;
-       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
-       if (err < 0)
-               return err;
+       sens_priv->settings[HFLIP_IDX] = val;
 
-       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
-       if (err < 0)
-               return err;
+       s5k83a_get_vflip(gspca_dev, &vflip);
 
-       /* set or zero seven bit, six is vflip */
-       data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK
-                       : (data[0] & 0x40) | S5K83A_FLIP_MASK;
-       err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
+       err = s5k83a_get_rotation(sd, &reg);
        if (err < 0)
                return err;
+       if (reg) {
+               val = !val;
+               vflip = !vflip;
+       }
 
-       data[0] = (val) ? 0x0a : 0x0b;
-       err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
-
+       err = s5k83a_set_flip_real(gspca_dev, vflip, val);
        return err;
 }
 
-int s5k83a_set_led_indication(struct sd *sd, u8 val)
+static int s5k83a_set_led_indication(struct sd *sd, u8 val)
 {
        int err = 0;
        u8 data[1];
@@ -454,5 +545,55 @@ int s5k83a_set_led_indication(struct sd *sd, u8 val)
 
        err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
 
-       return (err < 0) ? err : 0;
+       return err;
+}
+
+/* Get camera rotation on Acer notebooks */
+static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
+{
+       int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
+       *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
+       return err;
+}
+
+static void s5k83a_dump_registers(struct sd *sd)
+{
+       int address;
+       u8 page, old_page;
+       m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+
+       for (page = 0; page < 16; page++) {
+               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+               info("Dumping the s5k83a register state for page 0x%x", page);
+               for (address = 0; address <= 0xff; address++) {
+                       u8 val = 0;
+                       m5602_read_sensor(sd, address, &val, 1);
+                       info("register 0x%x contains 0x%x",
+                            address, val);
+               }
+       }
+       info("s5k83a register state dump complete");
+
+       for (page = 0; page < 16; page++) {
+               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+               info("Probing for which registers that are read/write "
+                               "for page 0x%x", page);
+               for (address = 0; address <= 0xff; address++) {
+                       u8 old_val, ctrl_val, test_val = 0xff;
+
+                       m5602_read_sensor(sd, address, &old_val, 1);
+                       m5602_write_sensor(sd, address, &test_val, 1);
+                       m5602_read_sensor(sd, address, &ctrl_val, 1);
+
+                       if (ctrl_val == test_val)
+                               info("register 0x%x is writeable", address);
+                       else
+                               info("register 0x%x is read only", address);
+
+                       /* Restore original val */
+                       m5602_write_sensor(sd, address, &old_val, 1);
+               }
+       }
+       info("Read/write register probing complete");
+       m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
 }
index 819ab25272bee72c9319e19663ee1c657584313b..7814b078acde3ca4cdd0aba521102000866dcc66 100644 (file)
 
 #include "m5602_sensor.h"
 
-#define S5K83A_FLIP                            0x01
-#define S5K83A_HFLIP_TUNE                      0x03
-#define S5K83A_VFLIP_TUNE                      0x05
-#define S5K83A_WHITENESS                       0x0a
-#define S5K83A_GAIN                            0x18
-#define S5K83A_BRIGHTNESS                      0x1b
-#define S5K83A_PAGE_MAP                                0xec
-
-#define S5K83A_DEFAULT_BRIGHTNESS              0x71
-#define S5K83A_DEFAULT_WHITENESS               0x7e
-#define S5K83A_DEFAULT_GAIN                    0x00
-#define S5K83A_MAXIMUM_GAIN                    0x3c
-#define S5K83A_FLIP_MASK                       0x10
+#define S5K83A_FLIP                    0x01
+#define S5K83A_HFLIP_TUNE              0x03
+#define S5K83A_VFLIP_TUNE              0x05
+#define S5K83A_BRIGHTNESS              0x0a
+#define S5K83A_EXPOSURE                        0x18
+#define S5K83A_GAIN                    0x1b
+#define S5K83A_PAGE_MAP                        0xec
+
+#define S5K83A_DEFAULT_GAIN            0x71
+#define S5K83A_DEFAULT_BRIGHTNESS      0x7e
+#define S5K83A_DEFAULT_EXPOSURE                0x00
+#define S5K83A_MAXIMUM_EXPOSURE                0x3c
+#define S5K83A_FLIP_MASK               0x10
 #define S5K83A_GPIO_LED_MASK           0x10
+#define S5K83A_GPIO_ROTATION_MASK      0x40
 
 /*****************************************************************************/
 
@@ -46,20 +47,7 @@ int s5k83a_probe(struct sd *sd);
 int s5k83a_init(struct sd *sd);
 int s5k83a_start(struct sd *sd);
 int s5k83a_stop(struct sd *sd);
-int s5k83a_power_down(struct sd *sd);
-
-int s5k83a_set_led_indication(struct sd *sd, u8 val);
-
-int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val);
-int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+void s5k83a_disconnect(struct sd *sd);
 
 static const struct m5602_sensor s5k83a = {
        .name = "S5K83A",
@@ -67,11 +55,18 @@ static const struct m5602_sensor s5k83a = {
        .init = s5k83a_init,
        .start = s5k83a_start,
        .stop = s5k83a_stop,
-       .power_down = s5k83a_power_down,
+       .disconnect = s5k83a_disconnect,
        .i2c_slave_id = 0x5a,
        .i2c_regW = 2,
 };
 
+struct s5k83a_priv {
+       /* We use another thread periodically
+          probing the orientation of the camera */
+       struct task_struct *rotation_thread;
+       s32 *settings;
+};
+
 static const unsigned char preinit_s5k83a[][4] =
 {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
@@ -108,8 +103,6 @@ static const unsigned char preinit_s5k83a[][4] =
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
        {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}
 };
 
 /* This could probably be considerably shortened.
@@ -117,86 +110,8 @@ static const unsigned char preinit_s5k83a[][4] =
 */
 static const unsigned char init_s5k83a[][4] =
 {
-       {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
-       {SENSOR, 0xaf, 0x01, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, 0x7b, 0xff, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, 0x01, 0x50, 0x00},
-       {SENSOR, 0x12, 0x20, 0x00},
-       {SENSOR, 0x17, 0x40, 0x00},
-       {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
-       {SENSOR, 0x1c, 0x00, 0x00},
-       {SENSOR, 0x02, 0x70, 0x00},
-       {SENSOR, 0x03, 0x0b, 0x00},
-       {SENSOR, 0x04, 0xf0, 0x00},
-       {SENSOR, 0x05, 0x0b, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, 0x06, 0x71, 0x00},
-       {SENSOR, 0x07, 0xe8, 0x00},
-       {SENSOR, 0x08, 0x02, 0x00},
-       {SENSOR, 0x09, 0x88, 0x00},
-       {SENSOR, 0x14, 0x00, 0x00},
-       {SENSOR, 0x15, 0x20, 0x00},
-       {SENSOR, 0x19, 0x00, 0x00},
-       {SENSOR, 0x1a, 0x98, 0x00},
-       {SENSOR, 0x0f, 0x02, 0x00},
-       {SENSOR, 0x10, 0xe5, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR_LONG, 0x14, 0x00, 0x20},
-       {SENSOR_LONG, 0x0d, 0x00, 0x7d},
-       {SENSOR_LONG, 0x1b, 0x0d, 0x05},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
-
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       /* The following sequence is useless after a clean boot
+          but is necessary after resume from suspend */
        {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
@@ -216,7 +131,7 @@ static const unsigned char init_s5k83a[][4] =
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
@@ -225,109 +140,34 @@ static const unsigned char init_s5k83a[][4] =
 
        {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
        {SENSOR, 0xaf, 0x01, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       /* ff ( init value )is very dark) || 71 and f0 better */
+       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
        {SENSOR, 0x7b, 0xff, 0x00},
        {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
        {SENSOR, 0x01, 0x50, 0x00},
        {SENSOR, 0x12, 0x20, 0x00},
        {SENSOR, 0x17, 0x40, 0x00},
-       {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
        {SENSOR, 0x1c, 0x00, 0x00},
        {SENSOR, 0x02, 0x70, 0x00},
-       /* some values like 0x10 give a blue-purple image */
        {SENSOR, 0x03, 0x0b, 0x00},
        {SENSOR, 0x04, 0xf0, 0x00},
        {SENSOR, 0x05, 0x0b, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       /* under 80 don't work, highter depend on value */
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
-
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
        {SENSOR, 0x06, 0x71, 0x00},
-       {SENSOR, 0x07, 0xe8, 0x00},
+       {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */
        {SENSOR, 0x08, 0x02, 0x00},
-       {SENSOR, 0x09, 0x88, 0x00},
+       {SENSOR, 0x09, 0x88, 0x00}, /* 648 */
        {SENSOR, 0x14, 0x00, 0x00},
-       {SENSOR, 0x15, 0x20, 0x00},
+       {SENSOR, 0x15, 0x20, 0x00}, /* 32 */
        {SENSOR, 0x19, 0x00, 0x00},
-       {SENSOR, 0x1a, 0x98, 0x00},
+       {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */
        {SENSOR, 0x0f, 0x02, 0x00},
-       {SENSOR, 0x10, 0xe5, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR_LONG, 0x14, 0x00, 0x20},
-       {SENSOR_LONG, 0x0d, 0x00, 0x7d},
-       {SENSOR_LONG, 0x1b, 0x0d, 0x05},
-
-       /* The following sequence is useless after a clean boot
-          but is necessary after resume from suspend */
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
-       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
-       {SENSOR, 0xaf, 0x01, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, 0x7b, 0xff, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, 0x01, 0x50, 0x00},
-       {SENSOR, 0x12, 0x20, 0x00},
-       {SENSOR, 0x17, 0x40, 0x00},
-       {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
-       {SENSOR, 0x1c, 0x00, 0x00},
-       {SENSOR, 0x02, 0x70, 0x00},
-       {SENSOR, 0x03, 0x0b, 0x00},
-       {SENSOR, 0x04, 0xf0, 0x00},
-       {SENSOR, 0x05, 0x0b, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */
+       /* normal colors
+       (this is value after boot, but after tries can be different) */
+       {SENSOR, 0x00, 0x06, 0x00},
+};
 
+static const unsigned char start_s5k83a[][4] =
+{
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -340,7 +180,7 @@ static const unsigned char init_s5k83a[][4] =
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
@@ -348,50 +188,10 @@ static const unsigned char init_s5k83a[][4] =
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */
        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, 0x06, 0x71, 0x00},
-       {SENSOR, 0x07, 0xe8, 0x00},
-       {SENSOR, 0x08, 0x02, 0x00},
-       {SENSOR, 0x09, 0x88, 0x00},
-       {SENSOR, 0x14, 0x00, 0x00},
-       {SENSOR, 0x15, 0x20, 0x00},
-       {SENSOR, 0x19, 0x00, 0x00},
-       {SENSOR, 0x1a, 0x98, 0x00},
-       {SENSOR, 0x0f, 0x02, 0x00},
-
-       {SENSOR, 0x10, 0xe5, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR_LONG, 0x14, 0x00, 0x20},
-       {SENSOR_LONG, 0x0d, 0x00, 0x7d},
-       {SENSOR_LONG, 0x1b, 0x0d, 0x05},
-
-       /* normal colors
-          (this is value after boot, but after tries can be different) */
-       {SENSOR, 0x00, 0x06, 0x00},
-
-       /* set default brightness */
-       {SENSOR_LONG, 0x14, 0x00, 0x20},
-       {SENSOR_LONG, 0x0d, 0x01, 0x00},
-       {SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3,
-                           S5K83A_DEFAULT_BRIGHTNESS >> 1},
-
-       /* set default whiteness */
-       {SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00},
-
-       /* set default gain */
-       {SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN},
-
-       /* set default flip */
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00},
-       {SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00},
-       {SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00}
-
 };
 
 #endif
index 0d3026936f2e90a8d4b842df62b73d03f0039581..edff4f1f586fdcef4c463834ca8523e6e2297241 100644 (file)
 
 #include "m5602_bridge.h"
 
+#define M5602_V4L2_CID_GREEN_BALANCE   (V4L2_CID_PRIVATE_BASE + 0)
+#define M5602_V4L2_CID_NOISE_SUPPRESION        (V4L2_CID_PRIVATE_BASE + 1)
+
 /* Enumerates all supported sensors */
 enum sensors {
        OV9650_SENSOR   = 1,
        S5K83A_SENSOR   = 2,
        S5K4AA_SENSOR   = 3,
        MT9M111_SENSOR  = 4,
-       PO1030_SENSOR   = 5
+       PO1030_SENSOR   = 5,
+       OV7660_SENSOR   = 6,
 };
 
 /* Enumerates all possible instruction types */
@@ -61,9 +65,6 @@ struct m5602_sensor {
 
        /* Executed when the device is disconnected */
        void (*disconnect)(struct sd *sd);
-
-       /* Performs a power down sequence */
-       int (*power_down)(struct sd *sd);
 };
 
 #endif
index 2a901a4a6f0039c54f607073b67282ffc7409874..30132513400cbc266209320e2c915252b6e1af8b 100644 (file)
@@ -321,6 +321,7 @@ static const struct sd_desc sd_desc = {
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x08ca, 0x0111)},
+       {USB_DEVICE(0x093a, 0x010f)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -347,8 +348,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 1fff37b79891253bbe24a88d761dd30b1ab2eb8b..188866ac6cefb8b96045ad497fecfbb3e32421b9 100644 (file)
@@ -50,6 +50,13 @@ static int i2c_detect_tries = 10;
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
+       char bridge;
+#define BRIDGE_OV511           0
+#define BRIDGE_OV511PLUS       1
+#define BRIDGE_OV518           2
+#define BRIDGE_OV518PLUS       3
+#define BRIDGE_OV519           4
+
        /* Determined by sensor type */
        __u8 sif;
 
@@ -87,6 +94,9 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
 
 static struct ctrl sd_ctrls[] = {
        {
@@ -164,7 +174,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static const struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format ov519_vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -176,7 +186,7 @@ static const struct v4l2_pix_format vga_mode[] = {
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0},
 };
-static const struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format ov519_sif_mode[] = {
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 8 + 590,
@@ -189,6 +199,47 @@ static const struct v4l2_pix_format sif_mode[] = {
                .priv = 0},
 };
 
+static const struct v4l2_pix_format ov518_vga_mode[] = {
+       {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+       {640, 480, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+};
+static const struct v4l2_pix_format ov518_sif_mode[] = {
+       {176, 144, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 40000,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+       {352, 288, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+};
+
+
+/* Registers common to OV511 / OV518 */
+#define R51x_SYS_RESET                 0x50
+#define R51x_SYS_INIT                  0x53
+#define R51x_SYS_SNAP                  0x52
+#define R51x_SYS_CUST_ID               0x5F
+#define R51x_COMP_LUT_BEGIN            0x80
+
+/* OV511 Camera interface register numbers */
+#define R511_SYS_LED_CTL               0x55    /* OV511+ only */
+#define        OV511_RESET_NOREGS              0x3F    /* All but OV511 & regs */
+
+/* OV518 Camera interface register numbers */
+#define R518_GPIO_OUT                  0x56    /* OV518(+) only */
+#define R518_GPIO_CTL                  0x57    /* OV518(+) only */
+
 /* OV519 Camera interface register numbers */
 #define OV519_R10_H_SIZE               0x10
 #define OV519_R11_V_SIZE               0x11
@@ -224,6 +275,8 @@ static const struct v4l2_pix_format sif_mode[] = {
 
 /* OV7610 registers */
 #define OV7610_REG_GAIN                0x00    /* gain setting (5:0) */
+#define OV7610_REG_BLUE                0x01    /* blue channel balance */
+#define OV7610_REG_RED         0x02    /* red channel balance */
 #define OV7610_REG_SAT         0x03    /* saturation */
 #define OV8610_REG_HUE         0x04    /* 04 reserved */
 #define OV7610_REG_CNT         0x05    /* Y contrast */
@@ -846,11 +899,12 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
 static int reg_w(struct sd *sd, __u16 index, __u8 value)
 {
        int ret;
+       int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 2 : 1;
 
        sd->gspca_dev.usb_buf[0] = value;
        ret = usb_control_msg(sd->gspca_dev.dev,
                        usb_sndctrlpipe(sd->gspca_dev.dev, 0),
-                       1,                      /* REQ_IO (ov518/519) */
+                       req,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index,
                        sd->gspca_dev.usb_buf, 1, 500);
@@ -864,10 +918,11 @@ static int reg_w(struct sd *sd, __u16 index, __u8 value)
 static int reg_r(struct sd *sd, __u16 index)
 {
        int ret;
+       int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 3 : 1;
 
        ret = usb_control_msg(sd->gspca_dev.dev,
                        usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
-                       1,                      /* REQ_IO */
+                       req,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index, sd->gspca_dev.usb_buf, 1, 500);
 
@@ -923,6 +978,28 @@ static int reg_w_mask(struct sd *sd,
        return reg_w(sd, index, value);
 }
 
+/*
+ * Writes multiple (n) byte value to a single register. Only valid with certain
+ * registers (0x30 and 0xc4 - 0xce).
+ */
+static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
+{
+       int ret;
+
+       *((u32 *)sd->gspca_dev.usb_buf) = __cpu_to_le32(value);
+
+       ret = usb_control_msg(sd->gspca_dev.dev,
+                       usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+                       1 /* REG_IO */,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0, index,
+                       sd->gspca_dev.usb_buf, n, 500);
+       if (ret < 0)
+               PDEBUG(D_ERR, "Write reg32 [%02x] %08x failed", index, value);
+       return ret;
+}
+
+
 /*
  * The OV518 I2C I/O procedure is different, hence, this function.
  * This is normally only called from i2c_w(). Note that this function
@@ -1014,20 +1091,47 @@ static inline int ov51x_stop(struct sd *sd)
 {
        PDEBUG(D_STREAM, "stopping");
        sd->stopped = 1;
-       return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               return reg_w(sd, R51x_SYS_RESET, 0x3d);
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               return reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
+       case BRIDGE_OV519:
+               return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+       }
+
+       return 0;
 }
 
 /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
  * actually stopped (for performance). */
 static inline int ov51x_restart(struct sd *sd)
 {
+       int rc;
+
        PDEBUG(D_STREAM, "restarting");
        if (!sd->stopped)
                return 0;
        sd->stopped = 0;
 
        /* Reinitialize the stream */
-       return reg_w(sd, OV519_SYS_RESET1, 0x00);
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               return reg_w(sd, R51x_SYS_RESET, 0x00);
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               rc = reg_w(sd, 0x2f, 0x80);
+               if (rc < 0)
+                       return rc;
+               return reg_w(sd, R51x_SYS_RESET, 0x00);
+       case BRIDGE_OV519:
+               return reg_w(sd, OV519_SYS_RESET1, 0x00);
+       }
+
+       return 0;
 }
 
 /* This does an initial reset of an OmniVision sensor and ensures that I2C
@@ -1287,16 +1391,161 @@ static int ov6xx0_configure(struct sd *sd)
 /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
 static void ov51x_led_control(struct sd *sd, int on)
 {
-       reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);   /* 0 / 1 */
+       switch (sd->bridge) {
+       /* OV511 has no LED control */
+       case BRIDGE_OV511PLUS:
+               reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0);
+               break;
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02);
+               break;
+       case BRIDGE_OV519:
+               reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);   /* 0 / 1 */
+               break;
+       }
 }
 
-/* this function is called at probe time */
-static int sd_config(struct gspca_dev *gspca_dev,
-                       const struct usb_device_id *id)
+/* OV518 quantization tables are 8x4 (instead of 8x8) */
+static int ov518_upload_quan_tables(struct sd *sd)
+{
+       const unsigned char yQuanTable518[] = {
+               5, 4, 5, 6, 6, 7, 7, 7,
+               5, 5, 5, 5, 6, 7, 7, 7,
+               6, 6, 6, 6, 7, 7, 7, 8,
+               7, 7, 6, 7, 7, 7, 8, 8
+       };
+
+       const unsigned char uvQuanTable518[] = {
+               6, 6, 6, 7, 7, 7, 7, 7,
+               6, 6, 6, 7, 7, 7, 7, 7,
+               6, 6, 6, 7, 7, 7, 7, 8,
+               7, 7, 7, 7, 7, 7, 8, 8
+       };
+
+       const unsigned char *pYTable = yQuanTable518;
+       const unsigned char *pUVTable = uvQuanTable518;
+       unsigned char val0, val1;
+       int i, rc, reg = R51x_COMP_LUT_BEGIN;
+
+       PDEBUG(D_PROBE, "Uploading quantization tables");
+
+       for (i = 0; i < 16; i++) {
+               val0 = *pYTable++;
+               val1 = *pYTable++;
+               val0 &= 0x0f;
+               val1 &= 0x0f;
+               val0 |= val1 << 4;
+               rc = reg_w(sd, reg, val0);
+               if (rc < 0)
+                       return rc;
+
+               val0 = *pUVTable++;
+               val1 = *pUVTable++;
+               val0 &= 0x0f;
+               val1 &= 0x0f;
+               val0 |= val1 << 4;
+               rc = reg_w(sd, reg + 16, val0);
+               if (rc < 0)
+                       return rc;
+
+               reg++;
+       }
+
+       return 0;
+}
+
+/* This initializes the OV518/OV518+ and the sensor */
+static int ov518_configure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct cam *cam;
+       int rc;
+
+       /* For 518 and 518+ */
+       static struct ov_regvals init_518[] = {
+               { R51x_SYS_RESET,       0x40 },
+               { R51x_SYS_INIT,        0xe1 },
+               { R51x_SYS_RESET,       0x3e },
+               { R51x_SYS_INIT,        0xe1 },
+               { R51x_SYS_RESET,       0x00 },
+               { R51x_SYS_INIT,        0xe1 },
+               { 0x46,                 0x00 },
+               { 0x5d,                 0x03 },
+       };
+
+       static struct ov_regvals norm_518[] = {
+               { R51x_SYS_SNAP,        0x02 }, /* Reset */
+               { R51x_SYS_SNAP,        0x01 }, /* Enable */
+               { 0x31,                 0x0f },
+               { 0x5d,                 0x03 },
+               { 0x24,                 0x9f },
+               { 0x25,                 0x90 },
+               { 0x20,                 0x00 },
+               { 0x51,                 0x04 },
+               { 0x71,                 0x19 },
+               { 0x2f,                 0x80 },
+       };
+
+       static struct ov_regvals norm_518_p[] = {
+               { R51x_SYS_SNAP,        0x02 }, /* Reset */
+               { R51x_SYS_SNAP,        0x01 }, /* Enable */
+               { 0x31,                 0x0f },
+               { 0x5d,                 0x03 },
+               { 0x24,                 0x9f },
+               { 0x25,                 0x90 },
+               { 0x20,                 0x60 },
+               { 0x51,                 0x02 },
+               { 0x71,                 0x19 },
+               { 0x40,                 0xff },
+               { 0x41,                 0x42 },
+               { 0x46,                 0x00 },
+               { 0x33,                 0x04 },
+               { 0x21,                 0x19 },
+               { 0x3f,                 0x10 },
+               { 0x2f,                 0x80 },
+       };
+
+       /* First 5 bits of custom ID reg are a revision ID on OV518 */
+       PDEBUG(D_PROBE, "Device revision %d",
+              0x1F & reg_r(sd, R51x_SYS_CUST_ID));
+
+       rc = write_regvals(sd, init_518, ARRAY_SIZE(init_518));
+       if (rc < 0)
+               return rc;
+
+       /* Set LED GPIO pin to output mode */
+       rc = reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);
+       if (rc < 0)
+               return rc;
 
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+               rc = write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
+               if (rc < 0)
+                       return rc;
+               break;
+       case BRIDGE_OV518PLUS:
+               rc = write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
+               if (rc < 0)
+                       return rc;
+               break;
+       }
+
+       rc = ov518_upload_quan_tables(sd);
+       if (rc < 0) {
+               PDEBUG(D_ERR, "Error uploading quantization tables");
+               return rc;
+       }
+
+       rc = reg_w(sd, 0x2f, 0x80);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int ov519_configure(struct sd *sd)
+{
        static const struct ov_regvals init_519[] = {
                { 0x5a,  0x6d }, /* EnableSystem */
                { 0x53,  0x9b },
@@ -1313,8 +1562,32 @@ static int sd_config(struct gspca_dev *gspca_dev,
                /* windows reads 0x55 at this point*/
        };
 
-       if (write_regvals(sd, init_519, ARRAY_SIZE(init_519)))
+       return write_regvals(sd, init_519, ARRAY_SIZE(init_519));
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+       int ret = 0;
+
+       sd->bridge = id->driver_info;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               ret = ov518_configure(gspca_dev);
+               break;
+       case BRIDGE_OV519:
+               ret = ov519_configure(sd);
+               break;
+       }
+
+       if (ret)
                goto error;
+
        ov51x_led_control(sd, 0);       /* turn LED off */
 
        /* Test for 76xx */
@@ -1360,12 +1633,26 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
 
        cam = &gspca_dev->cam;
-       if (!sd->sif) {
-               cam->cam_mode = vga_mode;
-               cam->nmodes = ARRAY_SIZE(vga_mode);
-       } else {
-               cam->cam_mode = sif_mode;
-               cam->nmodes = ARRAY_SIZE(sif_mode);
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               if (!sd->sif) {
+                       cam->cam_mode = ov518_vga_mode;
+                       cam->nmodes = ARRAY_SIZE(ov518_vga_mode);
+               } else {
+                       cam->cam_mode = ov518_sif_mode;
+                       cam->nmodes = ARRAY_SIZE(ov518_sif_mode);
+               }
+               break;
+       case BRIDGE_OV519:
+               if (!sd->sif) {
+                       cam->cam_mode = ov519_vga_mode;
+                       cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
+               } else {
+                       cam->cam_mode = ov519_sif_mode;
+                       cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
+               }
+               break;
        }
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
@@ -1422,6 +1709,106 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
+/* Sets up the OV518/OV518+ with the given image parameters
+ *
+ * OV518 needs a completely different approach, until we can figure out what
+ * the individual registers do. Also, only 15 FPS is supported now.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov518_mode_init_regs(struct sd *sd)
+{
+       int hsegs, vsegs;
+
+       /******** Set the mode ********/
+
+       reg_w(sd, 0x2b, 0);
+       reg_w(sd, 0x2c, 0);
+       reg_w(sd, 0x2d, 0);
+       reg_w(sd, 0x2e, 0);
+       reg_w(sd, 0x3b, 0);
+       reg_w(sd, 0x3c, 0);
+       reg_w(sd, 0x3d, 0);
+       reg_w(sd, 0x3e, 0);
+
+       if (sd->bridge == BRIDGE_OV518) {
+               /* Set 8-bit (YVYU) input format */
+               reg_w_mask(sd, 0x20, 0x08, 0x08);
+
+               /* Set 12-bit (4:2:0) output format */
+               reg_w_mask(sd, 0x28, 0x80, 0xf0);
+               reg_w_mask(sd, 0x38, 0x80, 0xf0);
+       } else {
+               reg_w(sd, 0x28, 0x80);
+               reg_w(sd, 0x38, 0x80);
+       }
+
+       hsegs = sd->gspca_dev.width / 16;
+       vsegs = sd->gspca_dev.height / 4;
+
+       reg_w(sd, 0x29, hsegs);
+       reg_w(sd, 0x2a, vsegs);
+
+       reg_w(sd, 0x39, hsegs);
+       reg_w(sd, 0x3a, vsegs);
+
+       /* Windows driver does this here; who knows why */
+       reg_w(sd, 0x2f, 0x80);
+
+       /******** Set the framerate (to 30 FPS) ********/
+       if (sd->bridge == BRIDGE_OV518PLUS)
+               sd->clockdiv = 1;
+       else
+               sd->clockdiv = 0;
+
+       /* Mode independent, but framerate dependent, regs */
+       reg_w(sd, 0x51, 0x04);  /* Clock divider; lower==faster */
+       reg_w(sd, 0x22, 0x18);
+       reg_w(sd, 0x23, 0xff);
+
+       if (sd->bridge == BRIDGE_OV518PLUS)
+               reg_w(sd, 0x21, 0x19);
+       else
+               reg_w(sd, 0x71, 0x17);  /* Compression-related? */
+
+       /* FIXME: Sensor-specific */
+       /* Bit 5 is what matters here. Of course, it is "reserved" */
+       i2c_w(sd, 0x54, 0x23);
+
+       reg_w(sd, 0x2f, 0x80);
+
+       if (sd->bridge == BRIDGE_OV518PLUS) {
+               reg_w(sd, 0x24, 0x94);
+               reg_w(sd, 0x25, 0x90);
+               ov518_reg_w32(sd, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(sd, 0xc6,    540, 2);     /* 21ch   */
+               ov518_reg_w32(sd, 0xc7,    540, 2);     /* 21ch   */
+               ov518_reg_w32(sd, 0xc8,    108, 2);     /* 6ch    */
+               ov518_reg_w32(sd, 0xca, 131098, 3);     /* 2001ah */
+               ov518_reg_w32(sd, 0xcb,    532, 2);     /* 214h   */
+               ov518_reg_w32(sd, 0xcc,   2400, 2);     /* 960h   */
+               ov518_reg_w32(sd, 0xcd,     32, 2);     /* 20h    */
+               ov518_reg_w32(sd, 0xce,    608, 2);     /* 260h   */
+       } else {
+               reg_w(sd, 0x24, 0x9f);
+               reg_w(sd, 0x25, 0x90);
+               ov518_reg_w32(sd, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(sd, 0xc6,    381, 2);     /* 17dh   */
+               ov518_reg_w32(sd, 0xc7,    381, 2);     /* 17dh   */
+               ov518_reg_w32(sd, 0xc8,    128, 2);     /* 80h    */
+               ov518_reg_w32(sd, 0xca, 183331, 3);     /* 2cc23h */
+               ov518_reg_w32(sd, 0xcb,    746, 2);     /* 2eah   */
+               ov518_reg_w32(sd, 0xcc,   1750, 2);     /* 6d6h   */
+               ov518_reg_w32(sd, 0xcd,     45, 2);     /* 2dh    */
+               ov518_reg_w32(sd, 0xce,    851, 2);     /* 353h   */
+       }
+
+       reg_w(sd, 0x2f, 0x80);
+
+       return 0;
+}
+
+
 /* Sets up the OV519 with the given image parameters
  *
  * OV519 needs a completely different approach, until we can figure out what
@@ -1740,6 +2127,11 @@ static int set_ov_sensor_window(struct sd *sd)
                hwebase = 0x3a;
                vwsbase = 0x05;
                vwebase = 0x06;
+               if (qvga) {
+                       /* HDG: this fixes U and V getting swapped */
+                       hwsbase--;
+                       vwsbase--;
+               }
                break;
        case SEN_OV7620:
                hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
@@ -1855,15 +2247,28 @@ static int set_ov_sensor_window(struct sd *sd)
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int ret;
+       int ret = 0;
 
-       ret = ov519_mode_init_regs(sd);
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               ret = ov518_mode_init_regs(sd);
+               break;
+       case BRIDGE_OV519:
+               ret = ov519_mode_init_regs(sd);
+               break;
+       }
        if (ret < 0)
                goto out;
+
        ret = set_ov_sensor_window(sd);
        if (ret < 0)
                goto out;
 
+       setcontrast(gspca_dev);
+       setbrightness(gspca_dev);
+       setcolors(gspca_dev);
+
        ret = ov51x_restart(sd);
        if (ret < 0)
                goto out;
@@ -1882,7 +2287,30 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        ov51x_led_control(sd, 0);
 }
 
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       PDEBUG(D_STREAM, "ov518_pkt_scan: %d bytes", len);
+
+       if (len & 7) {
+               len--;
+               PDEBUG(D_STREAM, "packet number: %d\n", (int)data[len]);
+       }
+
+       /* A false positive here is likely, until OVT gives me
+        * the definitive SOF/EOF format */
+       if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) {
+               gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0);
+       }
+
+       /* intermediate packet */
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
                        int len)                        /* iso packet length */
@@ -1926,6 +2354,27 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        data, len);
 }
 
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               break;
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               ov518_pkt_scan(gspca_dev, frame, data, len);
+               break;
+       case BRIDGE_OV519:
+               ov519_pkt_scan(gspca_dev, frame, data, len);
+               break;
+       }
+}
+
 /* -- management routines -- */
 
 static void setbrightness(struct gspca_dev *gspca_dev)
@@ -1970,6 +2419,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                break;
        case SEN_OV6630:
                i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
+               break;
        case SEN_OV8610: {
                static const __u8 ctab[] = {
                        0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
@@ -2136,19 +2586,21 @@ static const struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x041e, 0x4052)},
-       {USB_DEVICE(0x041e, 0x405f)},
-       {USB_DEVICE(0x041e, 0x4060)},
-       {USB_DEVICE(0x041e, 0x4061)},
-       {USB_DEVICE(0x041e, 0x4064)},
-       {USB_DEVICE(0x041e, 0x4068)},
-       {USB_DEVICE(0x045e, 0x028c)},
-       {USB_DEVICE(0x054c, 0x0154)},
-       {USB_DEVICE(0x054c, 0x0155)},
-       {USB_DEVICE(0x05a9, 0x0519)},
-       {USB_DEVICE(0x05a9, 0x0530)},
-       {USB_DEVICE(0x05a9, 0x4519)},
-       {USB_DEVICE(0x05a9, 0x8519)},
+       {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
+       {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS },
        {}
 };
 
index 19e0bc60de14aecf95708b7d6c922b49e063ce3a..4b528b37291188f858c6c130bcb20b71790d278a 100644 (file)
@@ -60,10 +60,23 @@ struct sd {
 static struct ctrl sd_ctrls[] = {
 };
 
-static const struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_yuyv_mode[] = {
        {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
         .bytesperline = 640 * 2,
         .sizeimage = 640 * 480 * 2,
+        .colorspace = V4L2_COLORSPACE_SRGB,
+        .priv = 0},
+};
+
+static const struct v4l2_pix_format vga_jpeg_mode[] = {
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+        .bytesperline = 320,
+        .sizeimage = 320 * 240 * 3 / 8 + 590,
+        .colorspace = V4L2_COLORSPACE_JPEG,
+        .priv = 1},
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+        .bytesperline = 640,
+        .sizeimage = 640 * 480 * 3 / 8 + 590,
         .colorspace = V4L2_COLORSPACE_JPEG,
         .priv = 0},
 };
@@ -244,7 +257,7 @@ static const u8 bridge_init_ov965x[][2] = {
 };
 
 static const u8 sensor_init_ov965x[][2] = {
-       {0x12, 0x80},   /* com7 - reset */
+       {0x12, 0x80},   /* com7 - SSCB reset */
        {0x00, 0x00},   /* gain */
        {0x01, 0x80},   /* blue */
        {0x02, 0x80},   /* red */
@@ -254,10 +267,10 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x0e, 0x61},   /* com5 */
        {0x0f, 0x42},   /* com6 */
        {0x11, 0x00},   /* clkrc */
-       {0x12, 0x02},   /* com7 */
+       {0x12, 0x02},   /* com7 - 15fps VGA YUYV */
        {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
        {0x14, 0x28},   /* com9 */
-       {0x16, 0x24},   /* rsvd16 */
+       {0x16, 0x24},   /* reg16 */
        {0x17, 0x1d},   /* hstart*/
        {0x18, 0xbd},   /* hstop */
        {0x19, 0x01},   /* vstrt */
@@ -269,24 +282,24 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x27, 0x08},   /* bbias */
        {0x28, 0x08},   /* gbbias */
        {0x29, 0x15},   /* gr com */
-       {0x2a, 0x00},
-       {0x2b, 0x00},
+       {0x2a, 0x00},   /* exhch */
+       {0x2b, 0x00},   /* exhcl */
        {0x2c, 0x08},   /* rbias */
        {0x32, 0xff},   /* href */
        {0x33, 0x00},   /* chlf */
-       {0x34, 0x3f},   /* arblm */
-       {0x35, 0x00},   /* rsvd35 */
-       {0x36, 0xf8},   /* rsvd36 */
-       {0x38, 0x72},   /* acom38 */
-       {0x39, 0x57},   /* ofon */
-       {0x3a, 0x80},   /* tslb */
-       {0x3b, 0xc4},
+       {0x34, 0x3f},   /* aref1 */
+       {0x35, 0x00},   /* aref2 */
+       {0x36, 0xf8},   /* aref3 */
+       {0x38, 0x72},   /* adc2 */
+       {0x39, 0x57},   /* aref4 */
+       {0x3a, 0x80},   /* tslb - yuyv */
+       {0x3b, 0xc4},   /* com11 - night mode 1/4 frame rate */
        {0x3d, 0x99},   /* com13 */
-       {0x3f, 0xc1},
+       {0x3f, 0xc1},   /* edge */
        {0x40, 0xc0},   /* com15 */
        {0x41, 0x40},   /* com16 */
-       {0x42, 0xc0},
-       {0x43, 0x0a},
+       {0x42, 0xc0},   /* com17 */
+       {0x43, 0x0a},   /* rsvd */
        {0x44, 0xf0},
        {0x45, 0x46},
        {0x46, 0x62},
@@ -297,22 +310,22 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x4c, 0x7f},
        {0x4d, 0x7f},
        {0x4e, 0x7f},
-       {0x4f, 0x98},
+       {0x4f, 0x98},   /* matrix */
        {0x50, 0x98},
        {0x51, 0x00},
        {0x52, 0x28},
        {0x53, 0x70},
        {0x54, 0x98},
-       {0x58, 0x1a},
-       {0x59, 0x85},
+       {0x58, 0x1a},   /* matrix coef sign */
+       {0x59, 0x85},   /* AWB control */
        {0x5a, 0xa9},
        {0x5b, 0x64},
        {0x5c, 0x84},
        {0x5d, 0x53},
        {0x5e, 0x0e},
-       {0x5f, 0xf0},
-       {0x60, 0xf0},
-       {0x61, 0xf0},
+       {0x5f, 0xf0},   /* AWB blue limit */
+       {0x60, 0xf0},   /* AWB red limit */
+       {0x61, 0xf0},   /* AWB green limit */
        {0x62, 0x00},   /* lcc1 */
        {0x63, 0x00},   /* lcc2 */
        {0x64, 0x02},   /* lcc3 */
@@ -324,15 +337,15 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x6d, 0x55},
        {0x6e, 0x00},
        {0x6f, 0x9d},
-       {0x70, 0x21},
+       {0x70, 0x21},   /* dnsth */
        {0x71, 0x78},
-       {0x72, 0x00},
-       {0x73, 0x01},
-       {0x74, 0x3a},
-       {0x75, 0x35},
+       {0x72, 0x00},   /* poidx */
+       {0x73, 0x01},   /* pckdv */
+       {0x74, 0x3a},   /* xindx */
+       {0x75, 0x35},   /* yindx */
        {0x76, 0x01},
        {0x77, 0x02},
-       {0x7a, 0x12},
+       {0x7a, 0x12},   /* gamma curve */
        {0x7b, 0x08},
        {0x7c, 0x16},
        {0x7d, 0x30},
@@ -349,33 +362,33 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x88, 0xe6},
        {0x89, 0xf2},
        {0x8a, 0x03},
-       {0x8c, 0x89},
+       {0x8c, 0x89},   /* com19 */
        {0x14, 0x28},   /* com9 */
        {0x90, 0x7d},
        {0x91, 0x7b},
-       {0x9d, 0x03},
-       {0x9e, 0x04},
+       {0x9d, 0x03},   /* lcc6 */
+       {0x9e, 0x04},   /* lcc7 */
        {0x9f, 0x7a},
        {0xa0, 0x79},
        {0xa1, 0x40},   /* aechm */
-       {0xa4, 0x50},
+       {0xa4, 0x50},   /* com21 */
        {0xa5, 0x68},   /* com26 */
-       {0xa6, 0x4a},
-       {0xa8, 0xc1},   /* acoma8 */
-       {0xa9, 0xef},   /* acoma9 */
+       {0xa6, 0x4a},   /* AWB green */
+       {0xa8, 0xc1},   /* refa8 */
+       {0xa9, 0xef},   /* refa9 */
        {0xaa, 0x92},
        {0xab, 0x04},
-       {0xac, 0x80},
+       {0xac, 0x80},   /* black level control */
        {0xad, 0x80},
        {0xae, 0x80},
        {0xaf, 0x80},
        {0xb2, 0xf2},
        {0xb3, 0x20},
-       {0xb4, 0x20},
+       {0xb4, 0x20},   /* ctrlb4 */
        {0xb5, 0x00},
        {0xb6, 0xaf},
        {0xbb, 0xae},
-       {0xbc, 0x7f},
+       {0xbc, 0x7f},   /* ADC channel offsets */
        {0xdb, 0x7f},
        {0xbe, 0x7f},
        {0xbf, 0x7f},
@@ -384,7 +397,7 @@ static const u8 sensor_init_ov965x[][2] = {
        {0xc2, 0x01},
        {0xc3, 0x4e},
        {0xc6, 0x85},
-       {0xc7, 0x80},
+       {0xc7, 0x80},   /* com24 */
        {0xc9, 0xe0},
        {0xca, 0xe8},
        {0xcb, 0xf0},
@@ -399,11 +412,11 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x58, 0x1a},
        {0xff, 0x41},   /* read 41, write ff 00 */
        {0x41, 0x40},   /* com16 */
-       {0xc5, 0x03},
-       {0x6a, 0x02},
+       {0xc5, 0x03},   /* 60 Hz banding filter */
+       {0x6a, 0x02},   /* 50 Hz banding filter */
 
-       {0x12, 0x62},   /* com7 - VGA + CIF */
-       {0x36, 0xfa},   /* rsvd36 */
+       {0x12, 0x62},   /* com7 - 30fps VGA YUV */
+       {0x36, 0xfa},   /* aref3 */
        {0x69, 0x0a},   /* hv */
        {0x8c, 0x89},   /* com22 */
        {0x14, 0x28},   /* com9 */
@@ -442,8 +455,8 @@ static const u8 bridge_init_ov965x_2[][2] = {
        {0x52, 0x3c},
        {0x53, 0x00},
        {0x54, 0x00},
-       {0x55, 0x00},
-       {0x57, 0x00},
+       {0x55, 0x00},   /* brightness */
+       {0x57, 0x00},   /* contrast 2 */
        {0x5c, 0x00},
        {0x5a, 0xa0},
        {0x5b, 0x78},
@@ -489,9 +502,66 @@ static const u8 sensor_init_ov965x_2[][2] = {
        {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
 };
 
+static const u8 sensor_start_ov965x[][2] = {
+       {0x12, 0x62},   /* com7 - 30fps VGA YUV */
+       {0x36, 0xfa},   /* aref3 */
+       {0x69, 0x0a},   /* hv */
+       {0x8c, 0x89},   /* com22 */
+       {0x14, 0x28},   /* com9 */
+       {0x3e, 0x0c},   /* com14 */
+       {0x41, 0x40},   /* com16 */
+       {0x72, 0x00},
+       {0x73, 0x00},
+       {0x74, 0x3a},
+       {0x75, 0x35},
+       {0x76, 0x01},
+       {0xc7, 0x80},   /* com24 */
+       {0x03, 0x12},   /* vref */
+       {0x17, 0x16},   /* hstart */
+       {0x18, 0x02},   /* hstop */
+       {0x19, 0x01},   /* vstrt */
+       {0x1a, 0x3d},   /* vstop */
+       {0x32, 0xff},   /* href */
+       {0xc0, 0xaa},
+       {}
+};
+
 static const u8 bridge_start_ov965x[][2] = {
+       {0x94, 0xaa},
+       {0xf1, 0x60},
+       {0xe5, 0x04},
+       {0xc0, 0x50},
+       {0xc1, 0x3c},
+       {0x8c, 0x00},
+       {0x8d, 0x1c},
+       {0x34, 0x05},
+       {}
+};
+
+static const u8 bridge_start_ov965x_vga[][2] = {
+       {0xc2, 0x0c},
+       {0xc3, 0xf9},
+       {0xda, 0x01},
+       {0x50, 0x00},
+       {0x51, 0xa0},
+       {0x52, 0x3c},
+       {0x53, 0x00},
+       {0x54, 0x00},
+       {0x55, 0x00},
+       {0x57, 0x00},
+       {0x5c, 0x00},
+       {0x5a, 0xa0},
+       {0x5b, 0x78},
+       {0x35, 0x02},
+       {0xd9, 0x10},
+       {0x94, 0x11},
+       {}
+};
+
+static const u8 bridge_start_ov965x_cif[][2] = {
        {0xc2, 0x4c},
        {0xc3, 0xf9},
+       {0xda, 0x00},
        {0x50, 0x00},
        {0x51, 0xa0},
        {0x52, 0x78},
@@ -500,30 +570,54 @@ static const u8 bridge_start_ov965x[][2] = {
        {0x55, 0x00},
        {0x57, 0x00},
        {0x5c, 0x00},
-       {0x5a, 0x28},
-       {0x5b, 0x1e},
-       {0x35, 0x00},
-       {0xd9, 0x21},
+       {0x5a, 0x50},
+       {0x5b, 0x3c},
+       {0x35, 0x02},
+       {0xd9, 0x10},
        {0x94, 0x11},
+       {}
 };
 
-static const u8 sensor_start_ov965x[][2] = {
-       {0x3b, 0xe4},
+static const u8 sensor_start_ov965x_vga[][2] = {
+       {0x3b, 0xc4},   /* com11 - night mode 1/4 frame rate */
+       {0x1e, 0x04},   /* mvfp */
+       {0x13, 0xe0},   /* com8 */
+       {0x00, 0x00},
+       {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
+       {0x11, 0x03},   /* clkrc */
+       {0x6b, 0x5a},   /* dblv */
+       {0x6a, 0x05},   /* 50 Hz banding filter */
+       {0xc5, 0x07},   /* 60 Hz banding filter */
+       {0xa2, 0x4b},   /* bd50 */
+       {0xa3, 0x3e},   /* bd60 */
+
+       {0x2d, 0x00},   /* advfl */
+       {}
+};
+
+static const u8 sensor_start_ov965x_cif[][2] = {
+       {0x3b, 0xe4},   /* com11 - night mode 1/4 frame rate */
        {0x1e, 0x04},   /* mvfp */
        {0x13, 0xe0},   /* com8 */
        {0x00, 0x00},
        {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
        {0x11, 0x01},   /* clkrc */
        {0x6b, 0x5a},   /* dblv */
-       {0x6a, 0x02},
-       {0xc5, 0x03},
-       {0xa2, 0x96},
-       {0xa3, 0x7d},
+       {0x6a, 0x02},   /* 50 Hz banding filter */
+       {0xc5, 0x03},   /* 60 Hz banding filter */
+       {0xa2, 0x96},   /* bd50 */
+       {0xa3, 0x7d},   /* bd60 */
+
        {0xff, 0x13},   /* read 13, write ff 00 */
        {0x13, 0xe7},
-       {0x3a, 0x80},
+       {0x3a, 0x80},   /* tslb - yuyv */
+       {}
+};
+
+static const u8 sensor_start_ov965x_2[][2] = {
        {0xff, 0x42},   /* read 42, write ff 00 */
-       {0x42, 0xc1},
+       {0x42, 0xc1},   /* com17 - 50 Hz filter */
+       {}
 };
 
 
@@ -705,11 +799,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam = &gspca_dev->cam;
 
-       cam->cam_mode = vga_mode;
-       cam->nmodes = ARRAY_SIZE(vga_mode);
+       if (sd->sensor == SENSOR_OV772X) {
+               cam->cam_mode = vga_yuyv_mode;
+               cam->nmodes = ARRAY_SIZE(vga_yuyv_mode);
 
-       cam->bulk_size = 16384;
-       cam->bulk_nurbs = 2;
+               cam->bulk = 1;
+               cam->bulk_size = 16384;
+               cam->bulk_nurbs = 2;
+       } else {                /* ov965x */
+               cam->cam_mode = vga_jpeg_mode;
+               cam->nmodes = ARRAY_SIZE(vga_jpeg_mode);
+       }
 
        return 0;
 }
@@ -778,6 +878,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       int mode;
 
        switch (sd->sensor) {
        case SENSOR_OV772X:
@@ -786,13 +887,28 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        default:
 /*     case SENSOR_OV965X: */
-               reg_w_array(gspca_dev, bridge_start_ov965x,
-                               ARRAY_SIZE(bridge_start_ov965x));
+
                sccb_w_array(gspca_dev, sensor_start_ov965x,
                                ARRAY_SIZE(sensor_start_ov965x));
+               reg_w_array(gspca_dev, bridge_start_ov965x,
+                               ARRAY_SIZE(bridge_start_ov965x));
+               mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+               if (mode != 0) {        /* 320x240 */
+                       reg_w_array(gspca_dev, bridge_start_ov965x_cif,
+                                       ARRAY_SIZE(bridge_start_ov965x_cif));
+                       sccb_w_array(gspca_dev, sensor_start_ov965x_cif,
+                                       ARRAY_SIZE(sensor_start_ov965x_cif));
+               } else {                /* 640x480 */
+                       reg_w_array(gspca_dev, bridge_start_ov965x_vga,
+                                       ARRAY_SIZE(bridge_start_ov965x_vga));
+                       sccb_w_array(gspca_dev, sensor_start_ov965x_vga,
+                                       ARRAY_SIZE(sensor_start_ov965x_vga));
+               }
+               sccb_w_array(gspca_dev, sensor_start_ov965x_2,
+                               ARRAY_SIZE(sensor_start_ov965x_2));
+               ov534_reg_write(gspca_dev, 0xe0, 0x00);
                ov534_reg_write(gspca_dev, 0xe0, 0x00);
                ov534_set_led(gspca_dev, 1);
-/*fixme: other sensor start omitted*/
        }
        return 0;
 }
@@ -832,9 +948,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
        __u32 this_pts;
        u16 this_fid;
        int remaining_len = len;
+       int payload_len;
 
+       payload_len = gspca_dev->cam.bulk ? 2048 : 2040;
        do {
-               len = min(remaining_len, 2040);         /*fixme: was 2048*/
+               len = min(remaining_len, payload_len);
 
                /* Payloads are prefixed with a UVC-style header.  We
                   consider a frame to start when the FID toggles, or the PTS
@@ -864,30 +982,27 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
 
                /* If PTS or FID has changed, start a new frame. */
                if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
-                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-                                       NULL, 0);
+                       if (gspca_dev->last_packet_type == INTER_PACKET)
+                               frame = gspca_frame_add(gspca_dev,
+                                                       LAST_PACKET, frame,
+                                                       NULL, 0);
                        sd->last_pts = this_pts;
                        sd->last_fid = this_fid;
-               }
-
-               /* Add the data from this payload */
-               gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
                                        data + 12, len - 12);
-
                /* If this packet is marked as EOF, end the frame */
-               if (data[1] & UVC_STREAM_EOF) {
+               } else if (data[1] & UVC_STREAM_EOF) {
                        sd->last_pts = 0;
-
-                       if (frame->data_end - frame->data !=
-                           gspca_dev->width * gspca_dev->height * 2) {
-                               PDEBUG(D_PACK, "short frame");
-                               goto discard;
-                       }
-
                        frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-                                               NULL, 0);
+                                               data + 12, len - 12);
+               } else {
+
+                       /* Add the data from this payload */
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                               data + 12, len - 12);
                }
 
+
                /* Done this payload */
                goto scan_next;
 
index 153d0a91d4b5c94acb6a06903f0862a3b9196398..cf3af8de6e971ca2422ec38330a3b57081b8f69c 100644 (file)
@@ -877,6 +877,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->cam_mode = sif_mode;
                cam->nmodes = ARRAY_SIZE(sif_mode);
        }
+       cam->npkt = 36;                 /* 36 packets per ISOC message */
+
        sd->brightness = BRIGHTNESS_DEF;
        sd->gain = GAIN_DEF;
        sd->exposure = EXPOSURE_DEF;
index c72e19d3ac370bbb00e883f233c1b49378ff96fa..dc6a6f11354a260ee01f389859c3b352fcb2e6d9 100644 (file)
@@ -62,7 +62,6 @@ struct sd {
 #define BRIDGE_SN9C105 1
 #define BRIDGE_SN9C110 2
 #define BRIDGE_SN9C120 3
-#define BRIDGE_SN9C325 4
        u8 sensor;                      /* Type of image sensor chip */
 #define SENSOR_HV7131R 0
 #define SENSOR_MI0360 1
@@ -354,9 +353,9 @@ static const u8 sn_ov7648[0x1c] = {
 
 static const u8 sn_ov7660[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
-       0x00,   0x61,   0x40,   0x00,   0x1a,   0x20,   0x20,   0x20,
+       0x00,   0x61,   0x40,   0x00,   0x1a,   0x00,   0x00,   0x00,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
-       0x81,   0x21,   0x07,   0x00,   0x00,   0x00,   0x00,   0x10,
+       0x81,   0x21,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
        0x03,   0x00,   0x01,   0x01,   0x08,   0x28,   0x1e,   0x20,
 /*     reg18   reg19   reg1a   reg1b */
@@ -757,6 +756,7 @@ static const u8 ov7660_sensor_init[][8] = {
        {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
        {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
        {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */
+       {0xb1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10},
 /****** (some exchanges in the win trace) ******/
        {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
                                                /* bits[3..0]reserved */
@@ -1065,9 +1065,9 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
        const u8 *reg9a;
        static const u8 reg9a_def[] =
-               {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
-       static const u8 reg9a_sn9c325[] =
-               {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+               {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
+       static const u8 reg9a_spec[] =
+               {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
        static const u8 regd4[] = {0x60, 0x00, 0x00};
 
        reg_w1(gspca_dev, 0xf1, 0x00);
@@ -1077,9 +1077,10 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
        reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
        reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
        reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);      /* jfm len was 3 */
-       switch (sd->bridge) {
-       case BRIDGE_SN9C325:
-               reg9a = reg9a_sn9c325;
+       switch (sd->sensor) {
+       case SENSOR_OV7660:
+       case SENSOR_SP80708:
+               reg9a = reg9a_spec;
                break;
        default:
                reg9a = reg9a_def;
@@ -1104,7 +1105,6 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
                reg_w1(gspca_dev, 0x17, 0x64);
                reg_w1(gspca_dev, 0x01, 0x42);
                break;
-/*jfm: from win trace */
        case SENSOR_OV7630:
                reg_w1(gspca_dev, 0x01, 0x61);
                reg_w1(gspca_dev, 0x17, 0xe2);
@@ -1114,18 +1114,15 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
        case SENSOR_OV7648:
                reg_w1(gspca_dev, 0x01, 0x63);
                reg_w1(gspca_dev, 0x17, 0x20);
+               reg_w1(gspca_dev, 0x01, 0x62);
                reg_w1(gspca_dev, 0x01, 0x42);
                break;
-/*jfm: from win trace */
        case SENSOR_OV7660:
-               if (sd->bridge == BRIDGE_SN9C120) {
-                       reg_w1(gspca_dev, 0x01, 0x61);
-                       reg_w1(gspca_dev, 0x17, 0x20);
-                       reg_w1(gspca_dev, 0x01, 0x60);
-                       reg_w1(gspca_dev, 0x01, 0x40);
-                       break;
-               }
-               /* fall thru */
+               reg_w1(gspca_dev, 0x01, 0x61);
+               reg_w1(gspca_dev, 0x17, 0x20);
+               reg_w1(gspca_dev, 0x01, 0x60);
+               reg_w1(gspca_dev, 0x01, 0x40);
+               break;
        case SENSOR_SP80708:
                reg_w1(gspca_dev, 0x01, 0x63);
                reg_w1(gspca_dev, 0x17, 0x20);
@@ -1134,6 +1131,9 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
                mdelay(100);
                reg_w1(gspca_dev, 0x02, 0x62);
                break;
+/*     case SENSOR_HV7131R: */
+/*     case SENSOR_MI0360: */
+/*     case SENSOR_MO4000: */
        default:
                reg_w1(gspca_dev, 0x01, 0x43);
                reg_w1(gspca_dev, 0x17, 0x61);
@@ -1280,6 +1280,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        cam = &gspca_dev->cam;
        cam->cam_mode = vga_mode;
        cam->nmodes = ARRAY_SIZE(vga_mode);
+       cam->npkt = 24;                 /* 24 packets per ISOC message */
 
        sd->bridge = id->driver_info >> 16;
        sd->sensor = id->driver_info >> 8;
@@ -1683,13 +1684,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
        case SENSOR_OV7648:
                reg17 = 0x20;
                break;
-/*jfm: from win trace */
        case SENSOR_OV7660:
-               if (sd->bridge == BRIDGE_SN9C120) {
-                       reg17 = 0xa0;
-                       break;
-               }
-               /* fall thru */
+               reg17 = 0xa0;
+               break;
        default:
                reg17 = 0x60;
                break;
@@ -1714,16 +1711,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w1(gspca_dev, 0x9a, 0x0a);
                reg_w1(gspca_dev, 0x99, 0x60);
                break;
+       case SENSOR_OV7660:
+               reg_w1(gspca_dev, 0x9a, 0x05);
+               if (sd->bridge == BRIDGE_SN9C105)
+                       reg_w1(gspca_dev, 0x99, 0xff);
+               else
+                       reg_w1(gspca_dev, 0x99, 0x5b);
+               break;
        case SENSOR_SP80708:
                reg_w1(gspca_dev, 0x9a, 0x05);
                reg_w1(gspca_dev, 0x99, 0x59);
                break;
-       case SENSOR_OV7660:
-               if (sd->bridge == BRIDGE_SN9C120) {
-                       reg_w1(gspca_dev, 0x9a, 0x05);
-                       break;
-               }
-               /* fall thru */
        default:
                reg_w1(gspca_dev, 0x9a, 0x08);
                reg_w1(gspca_dev, 0x99, 0x59);
@@ -2193,6 +2191,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
        {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
        {USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
+       {USB_DEVICE(0x06f8, 0x3008), BSI(SN9C105, OV7660, 0x21)},
        {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)},
 /* bw600.inf:
        {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */
@@ -2211,7 +2210,12 @@ static const __devinitdata struct usb_device_id device_table[] = {
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
 #endif
+       {USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/
 /*     {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
+       {USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/
+       {USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/
+       {USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/
+       {USB_DEVICE(0x0c45, 0x610e), BSI(SN9C120, OV7630, 0x21)}, /*sn9c128*/
 /*     {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
 /*     {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
        {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
index 6f38fa6d86b6ac7a03d9035d247d49a3d4b6e7eb..8806b2ff82bece047379e53fe80ef92c1e629ba2 100644 (file)
@@ -32,9 +32,6 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
-       __u8 packet[ISO_MAX_SIZE + 128];
-                                /* !! no more than 128 ff in an ISO packet */
-
        unsigned char brightness;
        unsigned char contrast;
        unsigned char colors;
@@ -906,7 +903,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
-       __u8 *s, *d;
        static __u8 ffd9[] = {0xff, 0xd9};
 
 /* frames are jpeg 4.1.1 without 0xff escape */
@@ -930,22 +926,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        }
 
        /* add 0x00 after 0xff */
-       for (i = len; --i >= 0; )
-               if (data[i] == 0xff)
-                       break;
-       if (i < 0) {                    /* no 0xff */
-               gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
-               return;
-       }
-       s = data;
-       d = sd->packet;
-       for (i = 0; i < len; i++) {
-               *d++ = *s++;
-               if (s[-1] == 0xff)
-                       *d++ = 0x00;
-       }
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                       sd->packet, d - sd->packet);
+       i = 0;
+       do {
+               if (data[i] == 0xff) {
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                       data, i + 1);
+                       len -= i;
+                       data += i;
+                       *data = 0x00;
+                       i = 0;
+               }
+               i++;
+       } while (i < len);
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
 static void setbrightness(struct gspca_dev *gspca_dev)
index 2acec58b1b9734cb67512100d2323416f15f3dae..ea8c9fe2e96198b8197faad7c6127767ce604507 100644 (file)
@@ -637,19 +637,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->nmodes = ARRAY_SIZE(vga_mode) - 1;
        sd->brightness = BRIGHTNESS_DEF;
 
-       if (sd->subtype == Nxultra) {
-               if (write_vector(gspca_dev, spca505b_init_data))
-                       return -EIO;
-       } else {
-               if (write_vector(gspca_dev, spca505_init_data))
-                       return -EIO;
-       }
        return 0;
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (write_vector(gspca_dev,
+                        sd->subtype == Nxultra
+                               ? spca505b_init_data
+                               : spca505_init_data))
+               return -EIO;
        return 0;
 }
 
index adacf8437661366a2c8d228f47fc499dd3479f02..2ed2669bac3ed178bdcfde8b36e50b7470ee3111 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SPCA508 chip based cameras subdriver
  *
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009 Jean-Francois Moine <http://moinejf.free.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,9 +30,9 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
-       unsigned char brightness;
+       u8 brightness;
 
-       char subtype;
+       u8 subtype;
 #define CreativeVista 0
 #define HamaUSBSightcam 1
 #define HamaUSBSightcam2 2
@@ -86,58 +86,34 @@ static const struct v4l2_pix_format sif_mode[] = {
 };
 
 /* Frame packet header offsets for the spca508 */
-#define SPCA508_OFFSET_TYPE 1
-#define SPCA508_OFFSET_COMPRESS 2
-#define SPCA508_OFFSET_FRAMSEQ 8
-#define SPCA508_OFFSET_WIN1LUM 11
 #define SPCA508_OFFSET_DATA 37
 
-#define SPCA508_SNAPBIT 0x20
-#define SPCA508_SNAPCTRL 0x40
-/*************** I2c ****************/
-#define SPCA508_INDEX_I2C_BASE 0x8800
-
 /*
  * Initialization data: this is the first set-up data written to the
  * device (before the open data).
  */
 static const u16 spca508_init_data[][2] =
 {
-       /*  line   URB      value, index */
-       /* 44274  1804 */ {0x0000, 0x870b},
-
-       /* 44299  1805 */ {0x0020, 0x8112},
-       /* Video drop enable, ISO streaming disable */
-       /* 44324  1806 */ {0x0003, 0x8111},
-       /* Reset compression & memory */
-       /* 44349  1807 */ {0x0000, 0x8110},
-       /* Disable all outputs */
-       /* 44372  1808 */ /* READ {0x0000, 0x8114} -> 0000: 00  */
-       /* 44398  1809 */ {0x0000, 0x8114},
-       /* SW GPIO data */
-       /* 44423  1810 */ {0x0008, 0x8110},
-       /* Enable charge pump output */
-       /* 44527  1811 */ {0x0002, 0x8116},
-       /* 200 kHz pump clock */
-       /* 44555  1812 */
-               /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
-       /* 44590  1813 */ {0x0003, 0x8111},
-       /* Reset compression & memory */
-       /* 44615  1814 */ {0x0000, 0x8111},
-       /* Normal mode (not reset) */
-       /* 44640  1815 */ {0x0098, 0x8110},
-       /* Enable charge pump output, sync.serial,external 2x clock */
-       /* 44665  1816 */ {0x000d, 0x8114},
-       /* SW GPIO data */
-       /* 44690  1817 */ {0x0002, 0x8116},
-       /* 200 kHz pump clock */
-       /* 44715  1818 */ {0x0020, 0x8112},
-       /* Video drop enable, ISO streaming disable */
+       {0x0000, 0x870b},
+
+       {0x0020, 0x8112},       /* Video drop enable, ISO streaming disable */
+       {0x0003, 0x8111},       /* Reset compression & memory */
+       {0x0000, 0x8110},       /* Disable all outputs */
+       /* READ {0x0000, 0x8114} -> 0000: 00  */
+       {0x0000, 0x8114},       /* SW GPIO data */
+       {0x0008, 0x8110},       /* Enable charge pump output */
+       {0x0002, 0x8116},       /* 200 kHz pump clock */
+       /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
+       {0x0003, 0x8111},       /* Reset compression & memory */
+       {0x0000, 0x8111},       /* Normal mode (not reset) */
+       {0x0098, 0x8110},
+               /* Enable charge pump output, sync.serial,external 2x clock */
+       {0x000d, 0x8114},       /* SW GPIO data */
+       {0x0002, 0x8116},       /* 200 kHz pump clock */
+       {0x0020, 0x8112},       /* Video drop enable, ISO streaming disable */
 /* --------------------------------------- */
-       /* 44740  1819 */ {0x000f, 0x8402},
-       /* memory bank */
-       /* 44765  1820 */ {0x0000, 0x8403},
-       /* ... address */
+       {0x000f, 0x8402},       /* memory bank */
+       {0x0000, 0x8403},       /* ... address */
 /* --------------------------------------- */
 /* 0x88__ is Synchronous Serial Interface. */
 /* TBD: This table could be expressed more compactly */
@@ -145,446 +121,384 @@ static const u16 spca508_init_data[][2] =
 /* TBD: Should see if the values in spca50x_i2c_data */
 /* would work with the VQ110 instead of the values */
 /* below. */
-       /* 44790  1821 */ {0x00c0, 0x8804},
-       /* SSI slave addr */
-       /* 44815  1822 */ {0x0008, 0x8802},
-       /* 375 Khz SSI clock */
-       /* 44838  1823 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 44862  1824 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 44888  1825 */ {0x0008, 0x8802},
-       /* 375 Khz SSI clock */
-       /* 44913  1826 */ {0x0012, 0x8801},
-       /* SSI reg addr */
-       /* 44938  1827 */ {0x0080, 0x8800},
-       /* SSI data to write */
-       /* 44961  1828 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 44985  1829 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45009  1830 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45035  1831 */ {0x0008, 0x8802},
-       /* 375 Khz SSI clock */
-       /* 45060  1832 */ {0x0012, 0x8801},
-       /* SSI reg addr */
-       /* 45085  1833 */ {0x0000, 0x8800},
-       /* SSI data to write */
-       /* 45108  1834 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45132  1835 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45156  1836 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45182  1837 */ {0x0008, 0x8802},
-       /* 375 Khz SSI clock */
-       /* 45207  1838 */ {0x0011, 0x8801},
-       /* SSI reg addr */
-       /* 45232  1839 */ {0x0040, 0x8800},
-       /* SSI data to write */
-       /* 45255  1840 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45279  1841 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45303  1842 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45329  1843 */ {0x0008, 0x8802},
-       /* 45354  1844 */ {0x0013, 0x8801},
-       /* 45379  1845 */ {0x0000, 0x8800},
-       /* 45402  1846 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45426  1847 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45450  1848 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45476  1849 */ {0x0008, 0x8802},
-       /* 45501  1850 */ {0x0014, 0x8801},
-       /* 45526  1851 */ {0x0000, 0x8800},
-       /* 45549  1852 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45573  1853 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45597  1854 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45623  1855 */ {0x0008, 0x8802},
-       /* 45648  1856 */ {0x0015, 0x8801},
-       /* 45673  1857 */ {0x0001, 0x8800},
-       /* 45696  1858 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45720  1859 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45744  1860 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45770  1861 */ {0x0008, 0x8802},
-       /* 45795  1862 */ {0x0016, 0x8801},
-       /* 45820  1863 */ {0x0003, 0x8800},
-       /* 45843  1864 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45867  1865 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45891  1866 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45917  1867 */ {0x0008, 0x8802},
-       /* 45942  1868 */ {0x0017, 0x8801},
-       /* 45967  1869 */ {0x0036, 0x8800},
-       /* 45990  1870 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46014  1871 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46038  1872 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46064  1873 */ {0x0008, 0x8802},
-       /* 46089  1874 */ {0x0018, 0x8801},
-       /* 46114  1875 */ {0x00ec, 0x8800},
-       /* 46137  1876 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46161  1877 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46185  1878 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46211  1879 */ {0x0008, 0x8802},
-       /* 46236  1880 */ {0x001a, 0x8801},
-       /* 46261  1881 */ {0x0094, 0x8800},
-       /* 46284  1882 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46308  1883 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46332  1884 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46358  1885 */ {0x0008, 0x8802},
-       /* 46383  1886 */ {0x001b, 0x8801},
-       /* 46408  1887 */ {0x0000, 0x8800},
-       /* 46431  1888 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46455  1889 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46479  1890 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46505  1891 */ {0x0008, 0x8802},
-       /* 46530  1892 */ {0x0027, 0x8801},
-       /* 46555  1893 */ {0x00a2, 0x8800},
-       /* 46578  1894 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46602  1895 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46626  1896 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46652  1897 */ {0x0008, 0x8802},
-       /* 46677  1898 */ {0x0028, 0x8801},
-       /* 46702  1899 */ {0x0040, 0x8800},
-       /* 46725  1900 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46749  1901 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46773  1902 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46799  1903 */ {0x0008, 0x8802},
-       /* 46824  1904 */ {0x002a, 0x8801},
-       /* 46849  1905 */ {0x0084, 0x8800},
-       /* 46872  1906 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46896  1907 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
-       /* 46920  1908 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46946  1909 */ {0x0008, 0x8802},
-       /* 46971  1910 */ {0x002b, 0x8801},
-       /* 46996  1911 */ {0x00a8, 0x8800},
-       /* 47019  1912 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47043  1913 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47067  1914 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47093  1915 */ {0x0008, 0x8802},
-       /* 47118  1916 */ {0x002c, 0x8801},
-       /* 47143  1917 */ {0x00fe, 0x8800},
-       /* 47166  1918 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47190  1919 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47214  1920 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47240  1921 */ {0x0008, 0x8802},
-       /* 47265  1922 */ {0x002d, 0x8801},
-       /* 47290  1923 */ {0x0003, 0x8800},
-       /* 47313  1924 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47337  1925 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47361  1926 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47387  1927 */ {0x0008, 0x8802},
-       /* 47412  1928 */ {0x0038, 0x8801},
-       /* 47437  1929 */ {0x0083, 0x8800},
-       /* 47460  1930 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47484  1931 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47508  1932 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47534  1933 */ {0x0008, 0x8802},
-       /* 47559  1934 */ {0x0033, 0x8801},
-       /* 47584  1935 */ {0x0081, 0x8800},
-       /* 47607  1936 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47631  1937 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47655  1938 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47681  1939 */ {0x0008, 0x8802},
-       /* 47706  1940 */ {0x0034, 0x8801},
-       /* 47731  1941 */ {0x004a, 0x8800},
-       /* 47754  1942 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47778  1943 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47802  1944 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47828  1945 */ {0x0008, 0x8802},
-       /* 47853  1946 */ {0x0039, 0x8801},
-       /* 47878  1947 */ {0x0000, 0x8800},
-       /* 47901  1948 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47925  1949 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47949  1950 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47975  1951 */ {0x0008, 0x8802},
-       /* 48000  1952 */ {0x0010, 0x8801},
-       /* 48025  1953 */ {0x00a8, 0x8800},
-       /* 48048  1954 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48072  1955 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48096  1956 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48122  1957 */ {0x0008, 0x8802},
-       /* 48147  1958 */ {0x0006, 0x8801},
-       /* 48172  1959 */ {0x0058, 0x8800},
-       /* 48195  1960 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48219  1961 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
-       /* 48243  1962 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48269  1963 */ {0x0008, 0x8802},
-       /* 48294  1964 */ {0x0000, 0x8801},
-       /* 48319  1965 */ {0x0004, 0x8800},
-       /* 48342  1966 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48366  1967 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48390  1968 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48416  1969 */ {0x0008, 0x8802},
-       /* 48441  1970 */ {0x0040, 0x8801},
-       /* 48466  1971 */ {0x0080, 0x8800},
-       /* 48489  1972 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48513  1973 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48537  1974 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48563  1975 */ {0x0008, 0x8802},
-       /* 48588  1976 */ {0x0041, 0x8801},
-       /* 48613  1977 */ {0x000c, 0x8800},
-       /* 48636  1978 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48660  1979 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48684  1980 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48710  1981 */ {0x0008, 0x8802},
-       /* 48735  1982 */ {0x0042, 0x8801},
-       /* 48760  1983 */ {0x000c, 0x8800},
-       /* 48783  1984 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48807  1985 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48831  1986 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48857  1987 */ {0x0008, 0x8802},
-       /* 48882  1988 */ {0x0043, 0x8801},
-       /* 48907  1989 */ {0x0028, 0x8800},
-       /* 48930  1990 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48954  1991 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48978  1992 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49004  1993 */ {0x0008, 0x8802},
-       /* 49029  1994 */ {0x0044, 0x8801},
-       /* 49054  1995 */ {0x0080, 0x8800},
-       /* 49077  1996 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49101  1997 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49125  1998 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49151  1999 */ {0x0008, 0x8802},
-       /* 49176  2000 */ {0x0045, 0x8801},
-       /* 49201  2001 */ {0x0020, 0x8800},
-       /* 49224  2002 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49248  2003 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49272  2004 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49298  2005 */ {0x0008, 0x8802},
-       /* 49323  2006 */ {0x0046, 0x8801},
-       /* 49348  2007 */ {0x0020, 0x8800},
-       /* 49371  2008 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49395  2009 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49419  2010 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49445  2011 */ {0x0008, 0x8802},
-       /* 49470  2012 */ {0x0047, 0x8801},
-       /* 49495  2013 */ {0x0080, 0x8800},
-       /* 49518  2014 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49542  2015 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49566  2016 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49592  2017 */ {0x0008, 0x8802},
-       /* 49617  2018 */ {0x0048, 0x8801},
-       /* 49642  2019 */ {0x004c, 0x8800},
-       /* 49665  2020 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49689  2021 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49713  2022 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49739  2023 */ {0x0008, 0x8802},
-       /* 49764  2024 */ {0x0049, 0x8801},
-       /* 49789  2025 */ {0x0084, 0x8800},
-       /* 49812  2026 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49836  2027 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49860  2028 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49886  2029 */ {0x0008, 0x8802},
-       /* 49911  2030 */ {0x004a, 0x8801},
-       /* 49936  2031 */ {0x0084, 0x8800},
-       /* 49959  2032 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49983  2033 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 50007  2034 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 50033  2035 */ {0x0008, 0x8802},
-       /* 50058  2036 */ {0x004b, 0x8801},
-       /* 50083  2037 */ {0x0084, 0x8800},
-       /* 50106  2038 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       {0x00c0, 0x8804},       /* SSI slave addr */
+       {0x0008, 0x8802},       /* 375 Khz SSI clock */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},       /* 375 Khz SSI clock */
+       {0x0012, 0x8801},       /* SSI reg addr */
+       {0x0080, 0x8800},       /* SSI data to write */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},       /* 375 Khz SSI clock */
+       {0x0012, 0x8801},       /* SSI reg addr */
+       {0x0000, 0x8800},       /* SSI data to write */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},       /* 375 Khz SSI clock */
+       {0x0011, 0x8801},       /* SSI reg addr */
+       {0x0040, 0x8800},       /* SSI data to write */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0013, 0x8801},
+       {0x0000, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0014, 0x8801},
+       {0x0000, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0015, 0x8801},
+       {0x0001, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0016, 0x8801},
+       {0x0003, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0017, 0x8801},
+       {0x0036, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0018, 0x8801},
+       {0x00ec, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x001a, 0x8801},
+       {0x0094, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x001b, 0x8801},
+       {0x0000, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0027, 0x8801},
+       {0x00a2, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0028, 0x8801},
+       {0x0040, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x002a, 0x8801},
+       {0x0084, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x002b, 0x8801},
+       {0x00a8, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x002c, 0x8801},
+       {0x00fe, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x002d, 0x8801},
+       {0x0003, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0038, 0x8801},
+       {0x0083, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0033, 0x8801},
+       {0x0081, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0034, 0x8801},
+       {0x004a, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0039, 0x8801},
+       {0x0000, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0010, 0x8801},
+       {0x00a8, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0006, 0x8801},
+       {0x0058, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0000, 0x8801},
+       {0x0004, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0040, 0x8801},
+       {0x0080, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0041, 0x8801},
+       {0x000c, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0042, 0x8801},
+       {0x000c, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0043, 0x8801},
+       {0x0028, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0044, 0x8801},
+       {0x0080, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0045, 0x8801},
+       {0x0020, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0046, 0x8801},
+       {0x0020, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0047, 0x8801},
+       {0x0080, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0048, 0x8801},
+       {0x004c, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0049, 0x8801},
+       {0x0084, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x004a, 0x8801},
+       {0x0084, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x004b, 0x8801},
+       {0x0084, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
        /* --------------------------------------- */
-       /* 50132  2039 */ {0x0012, 0x8700},
-       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
-       /* 50157  2040 */ {0x0000, 0x8701},
-       /* CKx1 clock delay adj */
-       /* 50182  2041 */ {0x0000, 0x8701},
-       /* CKx1 clock delay adj */
-       /* 50207  2042 */ {0x0001, 0x870c},
-       /* CKOx2 output */
+       {0x0012, 0x8700},       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+       {0x0000, 0x8701},       /* CKx1 clock delay adj */
+       {0x0000, 0x8701},       /* CKx1 clock delay adj */
+       {0x0001, 0x870c},       /* CKOx2 output */
        /* --------------------------------------- */
-       /* 50232  2043 */ {0x0080, 0x8600},
-       /* Line memory read counter (L) */
-       /* 50257  2044 */ {0x0001, 0x8606},
-       /* reserved */
-       /* 50282  2045 */ {0x0064, 0x8607},
-       /* Line memory read counter (H) 0x6480=25,728 */
-       /* 50307  2046 */ {0x002a, 0x8601},
-       /* CDSP sharp interpolation mode,
+       {0x0080, 0x8600},       /* Line memory read counter (L) */
+       {0x0001, 0x8606},       /* reserved */
+       {0x0064, 0x8607},       /* Line memory read counter (H) 0x6480=25,728 */
+       {0x002a, 0x8601},       /* CDSP sharp interpolation mode,
         *                      line sel for color sep, edge enhance enab */
-       /* 50332  2047 */ {0x0000, 0x8602},
-       /* optical black level for user settng = 0 */
-       /* 50357  2048 */ {0x0080, 0x8600},
-       /* Line memory read counter (L) */
-       /* 50382  2049 */ {0x000a, 0x8603},
-       /* optical black level calc mode: auto; optical black offset = 10 */
-       /* 50407  2050 */ {0x00df, 0x865b},
-       /* Horiz offset for valid pixels (L)=0xdf */
-       /* 50432  2051 */ {0x0012, 0x865c},
-       /* Vert offset for valid lines (L)=0x12 */
+       {0x0000, 0x8602},       /* optical black level for user settng = 0 */
+       {0x0080, 0x8600},       /* Line memory read counter (L) */
+       {0x000a, 0x8603},       /* optical black level calc mode:
+                                * auto; optical black offset = 10 */
+       {0x00df, 0x865b},       /* Horiz offset for valid pixels (L)=0xdf */
+       {0x0012, 0x865c},       /* Vert offset for valid lines (L)=0x12 */
 
 /* The following two lines seem to be the "wrong" resolution. */
 /* But perhaps these indicate the actual size of the sensor */
 /* rather than the size of the current video mode. */
-       /* 50457  2052 */ {0x0058, 0x865d},
-       /* Horiz valid pixels (*4) (L) = 352 */
-       /* 50482  2053 */ {0x0048, 0x865e},
-       /* Vert valid lines (*4) (L) = 288 */
-
-       /* 50507  2054 */ {0x0015, 0x8608},
-       /* A11 Coef ... */
-       /* 50532  2055 */ {0x0030, 0x8609},
-       /* 50557  2056 */ {0x00fb, 0x860a},
-       /* 50582  2057 */ {0x003e, 0x860b},
-       /* 50607  2058 */ {0x00ce, 0x860c},
-       /* 50632  2059 */ {0x00f4, 0x860d},
-       /* 50657  2060 */ {0x00eb, 0x860e},
-       /* 50682  2061 */ {0x00dc, 0x860f},
-       /* 50707  2062 */ {0x0039, 0x8610},
-       /* 50732  2063 */ {0x0001, 0x8611},
-       /* R offset for white balance ... */
-       /* 50757  2064 */ {0x0000, 0x8612},
-       /* 50782  2065 */ {0x0001, 0x8613},
-       /* 50807  2066 */ {0x0000, 0x8614},
-       /* 50832  2067 */ {0x005b, 0x8651},
-       /* R gain for white balance ... */
-       /* 50857  2068 */ {0x0040, 0x8652},
-       /* 50882  2069 */ {0x0060, 0x8653},
-       /* 50907  2070 */ {0x0040, 0x8654},
-       /* 50932  2071 */ {0x0000, 0x8655},
-       /* 50957  2072 */ {0x0001, 0x863f},
-       /* Fixed gamma correction enable, USB control,
-        *                       lum filter disable, lum noise clip disable */
-       /* 50982  2073 */ {0x00a1, 0x8656},
-       /* Window1 size 256x256, Windows2 size 64x64,
-        *               gamma look-up disable, new edge enhancement enable */
-       /* 51007  2074 */ {0x0018, 0x8657},
-       /* Edge gain high thresh */
-       /* 51032  2075 */ {0x0020, 0x8658},
-       /* Edge gain low thresh */
-       /* 51057  2076 */ {0x000a, 0x8659},
-       /* Edge bandwidth high threshold */
-       /* 51082  2077 */ {0x0005, 0x865a},
-       /* Edge bandwidth low threshold */
+       {0x0058, 0x865d},       /* Horiz valid pixels (*4) (L) = 352 */
+       {0x0048, 0x865e},       /* Vert valid lines (*4) (L) = 288 */
+
+       {0x0015, 0x8608},       /* A11 Coef ... */
+       {0x0030, 0x8609},
+       {0x00fb, 0x860a},
+       {0x003e, 0x860b},
+       {0x00ce, 0x860c},
+       {0x00f4, 0x860d},
+       {0x00eb, 0x860e},
+       {0x00dc, 0x860f},
+       {0x0039, 0x8610},
+       {0x0001, 0x8611},       /* R offset for white balance ... */
+       {0x0000, 0x8612},
+       {0x0001, 0x8613},
+       {0x0000, 0x8614},
+       {0x005b, 0x8651},       /* R gain for white balance ... */
+       {0x0040, 0x8652},
+       {0x0060, 0x8653},
+       {0x0040, 0x8654},
+       {0x0000, 0x8655},
+       {0x0001, 0x863f},       /* Fixed gamma correction enable, USB control,
+                                * lum filter disable, lum noise clip disable */
+       {0x00a1, 0x8656},       /* Window1 size 256x256, Windows2 size 64x64,
+                                * gamma look-up disable,
+                                * new edge enhancement enable */
+       {0x0018, 0x8657},       /* Edge gain high thresh */
+       {0x0020, 0x8658},       /* Edge gain low thresh */
+       {0x000a, 0x8659},       /* Edge bandwidth high threshold */
+       {0x0005, 0x865a},       /* Edge bandwidth low threshold */
        /* -------------------------------- */
-       /* 51107  2078 */ {0x0030, 0x8112},
-       /* Video drop enable, ISO streaming enable */
-       /* 51130  2079 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 51154  2080 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 51180  2081 */ {0xa908, 0x8802},
-       /* 51205  2082 */ {0x0034, 0x8801},
-       /* SSI reg addr */
-       /* 51230  2083 */ {0x00ca, 0x8800},
+       {0x0030, 0x8112},       /* Video drop enable, ISO streaming enable */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0xa908, 0x8802},
+       {0x0034, 0x8801},       /* SSI reg addr */
+       {0x00ca, 0x8800},
        /* SSI data to write */
-       /* 51253  2084 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 51277  2085 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 51301  2086 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 51327  2087 */ {0x1f08, 0x8802},
-       /* 51352  2088 */ {0x0006, 0x8801},
-       /* 51377  2089 */ {0x0080, 0x8800},
-       /* 51400  2090 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x1f08, 0x8802},
+       {0x0006, 0x8801},
+       {0x0080, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
 /* ----- Read back coefs we wrote earlier. */
-       /* 51424  2091 */ /* READ { 0, 0x0000, 0x8608 } -> 0000: 15  */
-       /* 51448  2092 */ /* READ { 0, 0x0000, 0x8609 } -> 0000: 30  */
-       /* 51472  2093 */ /* READ { 0, 0x0000, 0x860a } -> 0000: fb  */
-       /* 51496  2094 */ /* READ { 0, 0x0000, 0x860b } -> 0000: 3e  */
-       /* 51520  2095 */ /* READ { 0, 0x0000, 0x860c } -> 0000: ce  */
-       /* 51544  2096 */ /* READ { 0, 0x0000, 0x860d } -> 0000: f4  */
-       /* 51568  2097 */ /* READ { 0, 0x0000, 0x860e } -> 0000: eb  */
-       /* 51592  2098 */ /* READ { 0, 0x0000, 0x860f } -> 0000: dc  */
-       /* 51616  2099 */ /* READ { 0, 0x0000, 0x8610 } -> 0000: 39  */
-       /* 51640  2100 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 51664  2101 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 51690  2102 */ {0xb008, 0x8802},
-       /* 51715  2103 */ {0x0006, 0x8801},
-       /* 51740  2104 */ {0x007d, 0x8800},
-       /* 51763  2105 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0000, 0x8608 } -> 0000: 15  */
+       /* READ { 0x0000, 0x8609 } -> 0000: 30  */
+       /* READ { 0x0000, 0x860a } -> 0000: fb  */
+       /* READ { 0x0000, 0x860b } -> 0000: 3e  */
+       /* READ { 0x0000, 0x860c } -> 0000: ce  */
+       /* READ { 0x0000, 0x860d } -> 0000: f4  */
+       /* READ { 0x0000, 0x860e } -> 0000: eb  */
+       /* READ { 0x0000, 0x860f } -> 0000: dc  */
+       /* READ { 0x0000, 0x8610 } -> 0000: 39  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0xb008, 0x8802},
+       {0x0006, 0x8801},
+       {0x007d, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
 
        /* This chunk is seemingly redundant with */
        /* earlier commands (A11 Coef...), but if I disable it, */
        /* the image appears too dark.  Maybe there was some kind of */
        /* reset since the earlier commands, so this is necessary again. */
-       /* 51789  2106 */ {0x0015, 0x8608},
-       /* 51814  2107 */ {0x0030, 0x8609},
-       /* 51839  2108 */ {0xfffb, 0x860a},
-       /* 51864  2109 */ {0x003e, 0x860b},
-       /* 51889  2110 */ {0xffce, 0x860c},
-       /* 51914  2111 */ {0xfff4, 0x860d},
-       /* 51939  2112 */ {0xffeb, 0x860e},
-       /* 51964  2113 */ {0xffdc, 0x860f},
-       /* 51989  2114 */ {0x0039, 0x8610},
-       /* 52014  2115 */ {0x0018, 0x8657},
-
-       /* 52039  2116 */ {0x0000, 0x8508},
-       /* Disable compression. */
+       {0x0015, 0x8608},
+       {0x0030, 0x8609},
+       {0xfffb, 0x860a},
+       {0x003e, 0x860b},
+       {0xffce, 0x860c},
+       {0xfff4, 0x860d},
+       {0xffeb, 0x860e},
+       {0xffdc, 0x860f},
+       {0x0039, 0x8610},
+       {0x0018, 0x8657},
+
+       {0x0000, 0x8508},       /* Disable compression. */
        /* Previous line was:
-        * 52039  2116 *  { 0, 0x0021, 0x8508 },  * Enable compression. */
-       /* 52064  2117 */ {0x0032, 0x850b},
-       /* compression stuff */
-       /* 52089  2118 */ {0x0003, 0x8509},
-       /* compression stuff */
-       /* 52114  2119 */ {0x0011, 0x850a},
-       /* compression stuff */
-       /* 52139  2120 */ {0x0021, 0x850d},
-       /* compression stuff */
-       /* 52164  2121 */ {0x0010, 0x850c},
-       /* compression stuff */
-       /* 52189  2122 */ {0x0003, 0x8500},
-       /* *** Video mode: 160x120 */
-       /* 52214  2123 */ {0x0001, 0x8501},
-       /* Hardware-dominated snap control */
-       /* 52239  2124 */ {0x0061, 0x8656},
-       /* Window1 size 128x128, Windows2 size 128x128,
-        *              gamma look-up disable, new edge enhancement enable */
-       /* 52264  2125 */ {0x0018, 0x8617},
-       /* Window1 start X (*2) */
-       /* 52289  2126 */ {0x0008, 0x8618},
-       /* Window1 start Y (*2) */
-       /* 52314  2127 */ {0x0061, 0x8656},
-       /* Window1 size 128x128, Windows2 size 128x128,
-        *              gamma look-up disable, new edge enhancement enable */
-       /* 52339  2128 */ {0x0058, 0x8619},
-       /* Window2 start X (*2) */
-       /* 52364  2129 */ {0x0008, 0x861a},
-       /* Window2 start Y (*2) */
-       /* 52389  2130 */ {0x00ff, 0x8615},
-       /* High lum thresh for white balance */
-       /* 52414  2131 */ {0x0000, 0x8616},
-       /* Low lum thresh for white balance */
-       /* 52439  2132 */ {0x0012, 0x8700},
-       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
-       /* 52464  2133 */ {0x0012, 0x8700},
-       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
-       /* 52487  2134 */ /* READ { 0, 0x0000, 0x8656 } -> 0000: 61  */
-       /* 52513  2135 */ {0x0028, 0x8802},
-       /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
-       /* 52536  2136 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52560  2137 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
-       /* 52586  2138 */ {0x1f28, 0x8802},
-       /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
-       /* 52611  2139 */ {0x0010, 0x8801},
-       /* SSI reg addr */
-       /* 52636  2140 */ {0x003e, 0x8800},
-       /* SSI data to write */
-       /* 52659  2141 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52685  2142 */ {0x0028, 0x8802},
-       /* 52708  2143 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52732  2144 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
-       /* 52758  2145 */ {0x1f28, 0x8802},
-       /* 52783  2146 */ {0x0000, 0x8801},
-       /* 52808  2147 */ {0x001f, 0x8800},
-       /* 52831  2148 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52857  2149 */ {0x0001, 0x8602},
-       /* optical black level for user settning = 1 */
+       {0x0021, 0x8508},        * Enable compression. */
+       {0x0032, 0x850b},       /* compression stuff */
+       {0x0003, 0x8509},       /* compression stuff */
+       {0x0011, 0x850a},       /* compression stuff */
+       {0x0021, 0x850d},       /* compression stuff */
+       {0x0010, 0x850c},       /* compression stuff */
+       {0x0003, 0x8500},       /* *** Video mode: 160x120 */
+       {0x0001, 0x8501},       /* Hardware-dominated snap control */
+       {0x0061, 0x8656},       /* Window1 size 128x128, Windows2 size 128x128,
+                                * gamma look-up disable,
+                                * new edge enhancement enable */
+       {0x0018, 0x8617},       /* Window1 start X (*2) */
+       {0x0008, 0x8618},       /* Window1 start Y (*2) */
+       {0x0061, 0x8656},       /* Window1 size 128x128, Windows2 size 128x128,
+                                * gamma look-up disable,
+                                * new edge enhancement enable */
+       {0x0058, 0x8619},       /* Window2 start X (*2) */
+       {0x0008, 0x861a},       /* Window2 start Y (*2) */
+       {0x00ff, 0x8615},       /* High lum thresh for white balance */
+       {0x0000, 0x8616},       /* Low lum thresh for white balance */
+       {0x0012, 0x8700},       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+       {0x0012, 0x8700},       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+       /* READ { 0x0000, 0x8656 } -> 0000: 61  */
+       {0x0028, 0x8802},    /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 28  */
+       {0x1f28, 0x8802},    /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+       {0x0010, 0x8801},       /* SSI reg addr */
+       {0x003e, 0x8800},       /* SSI data to write */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       {0x0028, 0x8802},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 28  */
+       {0x1f28, 0x8802},
+       {0x0000, 0x8801},
+       {0x001f, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       {0x0001, 0x8602},    /* optical black level for user settning = 1 */
 
        /* Original: */
-       /* 52882  2150 */ {0x0023, 0x8700},
-       /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
-       /* 52907  2151 */ {0x000f, 0x8602},
-       /* optical black level for user settning = 15 */
-
-       /* 52932  2152 */ {0x0028, 0x8802},
-       /* 52955  2153 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52979  2154 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
-       /* 53005  2155 */ {0x1f28, 0x8802},
-       /* 53030  2156 */ {0x0010, 0x8801},
-       /* 53055  2157 */ {0x007b, 0x8800},
-       /* 53078  2158 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 53104  2159 */ {0x002f, 0x8651},
-       /* R gain for white balance ... */
-       /* 53129  2160 */ {0x0080, 0x8653},
-       /* 53152  2161 */ /* READ { 0, 0x0000, 0x8655 } -> 0000: 00  */
-       /* 53178  2162 */ {0x0000, 0x8655},
-
-       /* 53203  2163 */ {0x0030, 0x8112},
-       /* Video drop enable, ISO streaming enable */
-       /* 53228  2164 */ {0x0020, 0x8112},
-       /* Video drop enable, ISO streaming disable */
-       /* 53252  2165 */
-            /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
+       {0x0023, 0x8700},       /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
+       {0x000f, 0x8602},    /* optical black level for user settning = 15 */
+
+       {0x0028, 0x8802},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 28  */
+       {0x1f28, 0x8802},
+       {0x0010, 0x8801},
+       {0x007b, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       {0x002f, 0x8651},       /* R gain for white balance ... */
+       {0x0080, 0x8653},
+       /* READ { 0x0000, 0x8655 } -> 0000: 00  */
+       {0x0000, 0x8655},
+
+       {0x0030, 0x8112},       /* Video drop enable, ISO streaming enable */
+       {0x0020, 0x8112},       /* Video drop enable, ISO streaming disable */
+       /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
        {}
 };
 
@@ -592,27 +506,27 @@ static const u16 spca508_init_data[][2] =
  * Initialization data for Intel EasyPC Camera CS110
  */
 static const u16 spca508cs110_init_data[][2] = {
-       {0x0000, 0x870b}, /* Reset CTL3 */
-       {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
-       {0x0000, 0x8111}, /* Normal operation on reset */
+       {0x0000, 0x870b},       /* Reset CTL3 */
+       {0x0003, 0x8111},       /* Soft Reset compression, memory, TG & CDSP */
+       {0x0000, 0x8111},       /* Normal operation on reset */
        {0x0090, 0x8110},
                 /* External Clock 2x & Synchronous Serial Interface Output */
-       {0x0020, 0x8112}, /* Video Drop packet enable */
-       {0x0000, 0x8114}, /* Software GPIO output data */
+       {0x0020, 0x8112},       /* Video Drop packet enable */
+       {0x0000, 0x8114},       /* Software GPIO output data */
        {0x0001, 0x8114},
        {0x0001, 0x8114},
        {0x0001, 0x8114},
        {0x0003, 0x8114},
 
        /* Initial sequence Synchronous Serial Interface */
-       {0x000f, 0x8402}, /* Memory bank Address */
-       {0x0000, 0x8403}, /* Memory bank Address */
-       {0x00ba, 0x8804}, /* SSI Slave address */
-       {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
-       {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */
+       {0x000f, 0x8402},       /* Memory bank Address */
+       {0x0000, 0x8403},       /* Memory bank Address */
+       {0x00ba, 0x8804},       /* SSI Slave address */
+       {0x0010, 0x8802},       /* 93.75kHz SSI Clock Two DataByte */
+       {0x0010, 0x8802},       /* 93.75kHz SSI Clock two DataByte */
 
        {0x0001, 0x8801},
-       {0x000a, 0x8805},/* a - NWG: Dunno what this is about */
+       {0x000a, 0x8805},       /* a - NWG: Dunno what this is about */
        {0x0000, 0x8800},
        {0x0010, 0x8802},
 
@@ -646,459 +560,459 @@ static const u16 spca508cs110_init_data[][2] = {
        {0x0000, 0x8800},
        {0x0010, 0x8802},
 
-       {0x0002, 0x8704}, /* External input CKIx1 */
-       {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
-       {0x009a, 0x8600}, /* Line memory Read Counter (L) */
-       {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
-       {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */
-       {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */
+       {0x0002, 0x8704},       /* External input CKIx1 */
+       {0x0001, 0x8606},    /* 1 Line memory Read Counter (H) Result: (d)410 */
+       {0x009a, 0x8600},       /* Line memory Read Counter (L) */
+       {0x0001, 0x865b},       /* 1 Horizontal Offset for Valid Pixel(L) */
+       {0x0003, 0x865c},       /* 3 Vertical Offset for Valid Lines(L) */
+       {0x0058, 0x865d},       /* 58 Horizontal Valid Pixel Window(L) */
 
-       {0x0006, 0x8660}, /* Nibble data + input order */
+       {0x0006, 0x8660},       /* Nibble data + input order */
 
-       {0x000a, 0x8602}, /* Optical black level set to 0x0a */
-/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */
+       {0x000a, 0x8602},       /* Optical black level set to 0x0a */
+       {0x0000, 0x8603},       /* Optical black level Offset */
 
-/* 1962 *  {0, 0x0000, 0x8611},  * 0 R  Offset for white Balance */
-/* 1963 *  {0, 0x0000, 0x8612},  * 1 Gr Offset for white Balance */
-/* 1964 *  {0, 0x0000, 0x8613},  * 1f B  Offset for white Balance */
-/* 1965 *  {0, 0x0000, 0x8614},  * f0 Gb Offset for white Balance */
+/*     {0x0000, 0x8611},        * 0 R  Offset for white Balance */
+/*     {0x0000, 0x8612},        * 1 Gr Offset for white Balance */
+/*     {0x0000, 0x8613},        * 1f B  Offset for white Balance */
+/*     {0x0000, 0x8614},        * f0 Gb Offset for white Balance */
 
-       {0x0040, 0x8651}, /* 2b BLUE gain for white balance  good at all 60 */
-       {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */
-       {0x0035, 0x8653}, /* 26 RED gain for white balance */
-       {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */
+       {0x0040, 0x8651},   /* 2b BLUE gain for white balance  good at all 60 */
+       {0x0030, 0x8652},       /* 41 Gr Gain for white Balance (L) */
+       {0x0035, 0x8653},       /* 26 RED gain for white balance */
+       {0x0035, 0x8654},       /* 40Gb Gain for white Balance (L) */
        {0x0041, 0x863f},
              /* Fixed Gamma correction enabled (makes colours look better) */
 
-/* 2422 */ {0x0000, 0x8655},
-       /* High bits for white balance*****brightness control*** */
+       {0x0000, 0x8655},
+               /* High bits for white balance*****brightness control*** */
        {}
 };
 
 static const u16 spca508_sightcam_init_data[][2] = {
 /* This line seems to setup the frame/canvas */
-       /*368  */ {0x000f, 0x8402},
+       {0x000f, 0x8402},
 
 /* Theese 6 lines are needed to startup the webcam */
-       /*398  */ {0x0090, 0x8110},
-       /*399  */ {0x0001, 0x8114},
-       /*400  */ {0x0001, 0x8114},
-       /*401  */ {0x0001, 0x8114},
-       /*402  */ {0x0003, 0x8114},
-       /*403  */ {0x0080, 0x8804},
+       {0x0090, 0x8110},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0003, 0x8114},
+       {0x0080, 0x8804},
 
 /* This part seems to make the pictures darker? (autobrightness?) */
-       /*436  */ {0x0001, 0x8801},
-       /*437  */ {0x0004, 0x8800},
-       /*439  */ {0x0003, 0x8801},
-       /*440  */ {0x00e0, 0x8800},
-       /*442  */ {0x0004, 0x8801},
-       /*443  */ {0x00b4, 0x8800},
-       /*445  */ {0x0005, 0x8801},
-       /*446  */ {0x0000, 0x8800},
-
-       /*448  */ {0x0006, 0x8801},
-       /*449  */ {0x00e0, 0x8800},
-       /*451  */ {0x0007, 0x8801},
-       /*452  */ {0x000c, 0x8800},
+       {0x0001, 0x8801},
+       {0x0004, 0x8800},
+       {0x0003, 0x8801},
+       {0x00e0, 0x8800},
+       {0x0004, 0x8801},
+       {0x00b4, 0x8800},
+       {0x0005, 0x8801},
+       {0x0000, 0x8800},
+
+       {0x0006, 0x8801},
+       {0x00e0, 0x8800},
+       {0x0007, 0x8801},
+       {0x000c, 0x8800},
 
 /* This section is just needed, it probably
  * does something like the previous section,
  * but the cam won't start if it's not included.
  */
-       /*484  */ {0x0014, 0x8801},
-       /*485  */ {0x0008, 0x8800},
-       /*487  */ {0x0015, 0x8801},
-       /*488  */ {0x0067, 0x8800},
-       /*490  */ {0x0016, 0x8801},
-       /*491  */ {0x0000, 0x8800},
-       /*493  */ {0x0017, 0x8801},
-       /*494  */ {0x0020, 0x8800},
-       /*496  */ {0x0018, 0x8801},
-       /*497  */ {0x0044, 0x8800},
+       {0x0014, 0x8801},
+       {0x0008, 0x8800},
+       {0x0015, 0x8801},
+       {0x0067, 0x8800},
+       {0x0016, 0x8801},
+       {0x0000, 0x8800},
+       {0x0017, 0x8801},
+       {0x0020, 0x8800},
+       {0x0018, 0x8801},
+       {0x0044, 0x8800},
 
 /* Makes the picture darker - and the
  * cam won't start if not included
  */
-       /*505  */ {0x001e, 0x8801},
-       /*506  */ {0x00ea, 0x8800},
-       /*508  */ {0x001f, 0x8801},
-       /*509  */ {0x0001, 0x8800},
-       /*511  */ {0x0003, 0x8801},
-       /*512  */ {0x00e0, 0x8800},
+       {0x001e, 0x8801},
+       {0x00ea, 0x8800},
+       {0x001f, 0x8801},
+       {0x0001, 0x8800},
+       {0x0003, 0x8801},
+       {0x00e0, 0x8800},
 
 /* seems to place the colors ontop of each other #1 */
-       /*517  */ {0x0006, 0x8704},
-       /*518  */ {0x0001, 0x870c},
-       /*519  */ {0x0016, 0x8600},
-       /*520  */ {0x0002, 0x8606},
+       {0x0006, 0x8704},
+       {0x0001, 0x870c},
+       {0x0016, 0x8600},
+       {0x0002, 0x8606},
 
 /* if not included the pictures becomes _very_ dark */
-       /*521  */ {0x0064, 0x8607},
-       /*522  */ {0x003a, 0x8601},
-       /*523  */ {0x0000, 0x8602},
+       {0x0064, 0x8607},
+       {0x003a, 0x8601},
+       {0x0000, 0x8602},
 
 /* seems to place the colors ontop of each other #2 */
-       /*524  */ {0x0016, 0x8600},
-       /*525  */ {0x0018, 0x8617},
-       /*526  */ {0x0008, 0x8618},
-       /*527  */ {0x00a1, 0x8656},
+       {0x0016, 0x8600},
+       {0x0018, 0x8617},
+       {0x0008, 0x8618},
+       {0x00a1, 0x8656},
 
 /* webcam won't start if not included */
-       /*528  */ {0x0007, 0x865b},
-       /*529  */ {0x0001, 0x865c},
-       /*530  */ {0x0058, 0x865d},
-       /*531  */ {0x0048, 0x865e},
+       {0x0007, 0x865b},
+       {0x0001, 0x865c},
+       {0x0058, 0x865d},
+       {0x0048, 0x865e},
 
 /* adjusts the colors */
-       /*541  */ {0x0049, 0x8651},
-       /*542  */ {0x0040, 0x8652},
-       /*543  */ {0x004c, 0x8653},
-       /*544  */ {0x0040, 0x8654},
+       {0x0049, 0x8651},
+       {0x0040, 0x8652},
+       {0x004c, 0x8653},
+       {0x0040, 0x8654},
        {}
 };
 
 static const u16 spca508_sightcam2_init_data[][2] = {
-/* 35 */ {0x0020, 0x8112},
-
-/* 36 */ {0x000f, 0x8402},
-/* 37 */ {0x0000, 0x8403},
-
-/* 38 */ {0x0008, 0x8201},
-/* 39 */ {0x0008, 0x8200},
-/* 40 */ {0x0001, 0x8200},
-/* 43 */ {0x0009, 0x8201},
-/* 44 */ {0x0008, 0x8200},
-/* 45 */ {0x0001, 0x8200},
-/* 48 */ {0x000a, 0x8201},
-/* 49 */ {0x0008, 0x8200},
-/* 50 */ {0x0001, 0x8200},
-/* 53 */ {0x000b, 0x8201},
-/* 54 */ {0x0008, 0x8200},
-/* 55 */ {0x0001, 0x8200},
-/* 58 */ {0x000c, 0x8201},
-/* 59 */ {0x0008, 0x8200},
-/* 60 */ {0x0001, 0x8200},
-/* 63 */ {0x000d, 0x8201},
-/* 64 */ {0x0008, 0x8200},
-/* 65 */ {0x0001, 0x8200},
-/* 68 */ {0x000e, 0x8201},
-/* 69 */ {0x0008, 0x8200},
-/* 70 */ {0x0001, 0x8200},
-/* 73 */ {0x0007, 0x8201},
-/* 74 */ {0x0008, 0x8200},
-/* 75 */ {0x0001, 0x8200},
-/* 78 */ {0x000f, 0x8201},
-/* 79 */ {0x0008, 0x8200},
-/* 80 */ {0x0001, 0x8200},
-
-/* 84 */ {0x0018, 0x8660},
-/* 85 */ {0x0010, 0x8201},
-
-/* 86 */ {0x0008, 0x8200},
-/* 87 */ {0x0001, 0x8200},
-/* 90 */ {0x0011, 0x8201},
-/* 91 */ {0x0008, 0x8200},
-/* 92 */ {0x0001, 0x8200},
-
-/* 95 */ {0x0000, 0x86b0},
-/* 96 */ {0x0034, 0x86b1},
-/* 97 */ {0x0000, 0x86b2},
-/* 98 */ {0x0049, 0x86b3},
-/* 99 */ {0x0000, 0x86b4},
-/* 100 */ {0x0000, 0x86b4},
-
-/* 101 */ {0x0012, 0x8201},
-/* 102 */ {0x0008, 0x8200},
-/* 103 */ {0x0001, 0x8200},
-/* 106 */ {0x0013, 0x8201},
-/* 107 */ {0x0008, 0x8200},
-/* 108 */ {0x0001, 0x8200},
-
-/* 111 */ {0x0001, 0x86b0},
-/* 112 */ {0x00aa, 0x86b1},
-/* 113 */ {0x0000, 0x86b2},
-/* 114 */ {0x00e4, 0x86b3},
-/* 115 */ {0x0000, 0x86b4},
-/* 116 */ {0x0000, 0x86b4},
-
-/* 118 */ {0x0018, 0x8660},
-
-/* 119 */ {0x0090, 0x8110},
-/* 120 */ {0x0001, 0x8114},
-/* 121 */ {0x0001, 0x8114},
-/* 122 */ {0x0001, 0x8114},
-/* 123 */ {0x0003, 0x8114},
-
-/* 124 */ {0x0080, 0x8804},
-/* 157 */ {0x0003, 0x8801},
-/* 158 */ {0x0012, 0x8800},
-/* 160 */ {0x0004, 0x8801},
-/* 161 */ {0x0005, 0x8800},
-/* 163 */ {0x0005, 0x8801},
-/* 164 */ {0x0000, 0x8800},
-/* 166 */ {0x0006, 0x8801},
-/* 167 */ {0x0000, 0x8800},
-/* 169 */ {0x0007, 0x8801},
-/* 170 */ {0x0000, 0x8800},
-/* 172 */ {0x0008, 0x8801},
-/* 173 */ {0x0005, 0x8800},
-/* 175 */ {0x000a, 0x8700},
-/* 176 */ {0x000e, 0x8801},
-/* 177 */ {0x0004, 0x8800},
-/* 179 */ {0x0005, 0x8801},
-/* 180 */ {0x0047, 0x8800},
-/* 182 */ {0x0006, 0x8801},
-/* 183 */ {0x0000, 0x8800},
-/* 185 */ {0x0007, 0x8801},
-/* 186 */ {0x00c0, 0x8800},
-/* 188 */ {0x0008, 0x8801},
-/* 189 */ {0x0003, 0x8800},
-/* 191 */ {0x0013, 0x8801},
-/* 192 */ {0x0001, 0x8800},
-/* 194 */ {0x0009, 0x8801},
-/* 195 */ {0x0000, 0x8800},
-/* 197 */ {0x000a, 0x8801},
-/* 198 */ {0x0000, 0x8800},
-/* 200 */ {0x000b, 0x8801},
-/* 201 */ {0x0000, 0x8800},
-/* 203 */ {0x000c, 0x8801},
-/* 204 */ {0x0000, 0x8800},
-/* 206 */ {0x000e, 0x8801},
-/* 207 */ {0x0004, 0x8800},
-/* 209 */ {0x000f, 0x8801},
-/* 210 */ {0x0000, 0x8800},
-/* 212 */ {0x0010, 0x8801},
-/* 213 */ {0x0006, 0x8800},
-/* 215 */ {0x0011, 0x8801},
-/* 216 */ {0x0006, 0x8800},
-/* 218 */ {0x0012, 0x8801},
-/* 219 */ {0x0000, 0x8800},
-/* 221 */ {0x0013, 0x8801},
-/* 222 */ {0x0001, 0x8800},
-
-/* 224 */ {0x000a, 0x8700},
-/* 225 */ {0x0000, 0x8702},
-/* 226 */ {0x0000, 0x8703},
-/* 227 */ {0x00c2, 0x8704},
-/* 228 */ {0x0001, 0x870c},
-
-/* 229 */ {0x0044, 0x8600},
-/* 230 */ {0x0002, 0x8606},
-/* 231 */ {0x0064, 0x8607},
-/* 232 */ {0x003a, 0x8601},
-/* 233 */ {0x0008, 0x8602},
-/* 234 */ {0x0044, 0x8600},
-/* 235 */ {0x0018, 0x8617},
-/* 236 */ {0x0008, 0x8618},
-/* 237 */ {0x00a1, 0x8656},
-/* 238 */ {0x0004, 0x865b},
-/* 239 */ {0x0002, 0x865c},
-/* 240 */ {0x0058, 0x865d},
-/* 241 */ {0x0048, 0x865e},
-/* 242 */ {0x0012, 0x8608},
-/* 243 */ {0x002c, 0x8609},
-/* 244 */ {0x0002, 0x860a},
-/* 245 */ {0x002c, 0x860b},
-/* 246 */ {0x00db, 0x860c},
-/* 247 */ {0x00f9, 0x860d},
-/* 248 */ {0x00f1, 0x860e},
-/* 249 */ {0x00e3, 0x860f},
-/* 250 */ {0x002c, 0x8610},
-/* 251 */ {0x006c, 0x8651},
-/* 252 */ {0x0041, 0x8652},
-/* 253 */ {0x0059, 0x8653},
-/* 254 */ {0x0040, 0x8654},
-/* 255 */ {0x00fa, 0x8611},
-/* 256 */ {0x00ff, 0x8612},
-/* 257 */ {0x00f8, 0x8613},
-/* 258 */ {0x0000, 0x8614},
-/* 259 */ {0x0001, 0x863f},
-/* 260 */ {0x0000, 0x8640},
-/* 261 */ {0x0026, 0x8641},
-/* 262 */ {0x0045, 0x8642},
-/* 263 */ {0x0060, 0x8643},
-/* 264 */ {0x0075, 0x8644},
-/* 265 */ {0x0088, 0x8645},
-/* 266 */ {0x009b, 0x8646},
-/* 267 */ {0x00b0, 0x8647},
-/* 268 */ {0x00c5, 0x8648},
-/* 269 */ {0x00d2, 0x8649},
-/* 270 */ {0x00dc, 0x864a},
-/* 271 */ {0x00e5, 0x864b},
-/* 272 */ {0x00eb, 0x864c},
-/* 273 */ {0x00f0, 0x864d},
-/* 274 */ {0x00f6, 0x864e},
-/* 275 */ {0x00fa, 0x864f},
-/* 276 */ {0x00ff, 0x8650},
-/* 277 */ {0x0060, 0x8657},
-/* 278 */ {0x0010, 0x8658},
-/* 279 */ {0x0018, 0x8659},
-/* 280 */ {0x0005, 0x865a},
-/* 281 */ {0x0018, 0x8660},
-/* 282 */ {0x0003, 0x8509},
-/* 283 */ {0x0011, 0x850a},
-/* 284 */ {0x0032, 0x850b},
-/* 285 */ {0x0010, 0x850c},
-/* 286 */ {0x0021, 0x850d},
-/* 287 */ {0x0001, 0x8500},
-/* 288 */ {0x0000, 0x8508},
-/* 289 */ {0x0012, 0x8608},
-/* 290 */ {0x002c, 0x8609},
-/* 291 */ {0x0002, 0x860a},
-/* 292 */ {0x0039, 0x860b},
-/* 293 */ {0x00d0, 0x860c},
-/* 294 */ {0x00f7, 0x860d},
-/* 295 */ {0x00ed, 0x860e},
-/* 296 */ {0x00db, 0x860f},
-/* 297 */ {0x0039, 0x8610},
-/* 298 */ {0x0012, 0x8657},
-/* 299 */ {0x000c, 0x8619},
-/* 300 */ {0x0004, 0x861a},
-/* 301 */ {0x00a1, 0x8656},
-/* 302 */ {0x00c8, 0x8615},
-/* 303 */ {0x0032, 0x8616},
-
-/* 306 */ {0x0030, 0x8112},
-/* 313 */ {0x0020, 0x8112},
-/* 314 */ {0x0020, 0x8112},
-/* 315 */ {0x000f, 0x8402},
-/* 316 */ {0x0000, 0x8403},
-
-/* 317 */ {0x0090, 0x8110},
-/* 318 */ {0x0001, 0x8114},
-/* 319 */ {0x0001, 0x8114},
-/* 320 */ {0x0001, 0x8114},
-/* 321 */ {0x0003, 0x8114},
-/* 322 */ {0x0080, 0x8804},
-
-/* 355 */ {0x0003, 0x8801},
-/* 356 */ {0x0012, 0x8800},
-/* 358 */ {0x0004, 0x8801},
-/* 359 */ {0x0005, 0x8800},
-/* 361 */ {0x0005, 0x8801},
-/* 362 */ {0x0047, 0x8800},
-/* 364 */ {0x0006, 0x8801},
-/* 365 */ {0x0000, 0x8800},
-/* 367 */ {0x0007, 0x8801},
-/* 368 */ {0x00c0, 0x8800},
-/* 370 */ {0x0008, 0x8801},
-/* 371 */ {0x0003, 0x8800},
-/* 373 */ {0x000a, 0x8700},
-/* 374 */ {0x000e, 0x8801},
-/* 375 */ {0x0004, 0x8800},
-/* 377 */ {0x0005, 0x8801},
-/* 378 */ {0x0047, 0x8800},
-/* 380 */ {0x0006, 0x8801},
-/* 381 */ {0x0000, 0x8800},
-/* 383 */ {0x0007, 0x8801},
-/* 384 */ {0x00c0, 0x8800},
-/* 386 */ {0x0008, 0x8801},
-/* 387 */ {0x0003, 0x8800},
-/* 389 */ {0x0013, 0x8801},
-/* 390 */ {0x0001, 0x8800},
-/* 392 */ {0x0009, 0x8801},
-/* 393 */ {0x0000, 0x8800},
-/* 395 */ {0x000a, 0x8801},
-/* 396 */ {0x0000, 0x8800},
-/* 398 */ {0x000b, 0x8801},
-/* 399 */ {0x0000, 0x8800},
-/* 401 */ {0x000c, 0x8801},
-/* 402 */ {0x0000, 0x8800},
-/* 404 */ {0x000e, 0x8801},
-/* 405 */ {0x0004, 0x8800},
-/* 407 */ {0x000f, 0x8801},
-/* 408 */ {0x0000, 0x8800},
-/* 410 */ {0x0010, 0x8801},
-/* 411 */ {0x0006, 0x8800},
-/* 413 */ {0x0011, 0x8801},
-/* 414 */ {0x0006, 0x8800},
-/* 416 */ {0x0012, 0x8801},
-/* 417 */ {0x0000, 0x8800},
-/* 419 */ {0x0013, 0x8801},
-/* 420 */ {0x0001, 0x8800},
-/* 422 */ {0x000a, 0x8700},
-/* 423 */ {0x0000, 0x8702},
-/* 424 */ {0x0000, 0x8703},
-/* 425 */ {0x00c2, 0x8704},
-/* 426 */ {0x0001, 0x870c},
-/* 427 */ {0x0044, 0x8600},
-/* 428 */ {0x0002, 0x8606},
-/* 429 */ {0x0064, 0x8607},
-/* 430 */ {0x003a, 0x8601},
-/* 431 */ {0x0008, 0x8602},
-/* 432 */ {0x0044, 0x8600},
-/* 433 */ {0x0018, 0x8617},
-/* 434 */ {0x0008, 0x8618},
-/* 435 */ {0x00a1, 0x8656},
-/* 436 */ {0x0004, 0x865b},
-/* 437 */ {0x0002, 0x865c},
-/* 438 */ {0x0058, 0x865d},
-/* 439 */ {0x0048, 0x865e},
-/* 440 */ {0x0012, 0x8608},
-/* 441 */ {0x002c, 0x8609},
-/* 442 */ {0x0002, 0x860a},
-/* 443 */ {0x002c, 0x860b},
-/* 444 */ {0x00db, 0x860c},
-/* 445 */ {0x00f9, 0x860d},
-/* 446 */ {0x00f1, 0x860e},
-/* 447 */ {0x00e3, 0x860f},
-/* 448 */ {0x002c, 0x8610},
-/* 449 */ {0x006c, 0x8651},
-/* 450 */ {0x0041, 0x8652},
-/* 451 */ {0x0059, 0x8653},
-/* 452 */ {0x0040, 0x8654},
-/* 453 */ {0x00fa, 0x8611},
-/* 454 */ {0x00ff, 0x8612},
-/* 455 */ {0x00f8, 0x8613},
-/* 456 */ {0x0000, 0x8614},
-/* 457 */ {0x0001, 0x863f},
-/* 458 */ {0x0000, 0x8640},
-/* 459 */ {0x0026, 0x8641},
-/* 460 */ {0x0045, 0x8642},
-/* 461 */ {0x0060, 0x8643},
-/* 462 */ {0x0075, 0x8644},
-/* 463 */ {0x0088, 0x8645},
-/* 464 */ {0x009b, 0x8646},
-/* 465 */ {0x00b0, 0x8647},
-/* 466 */ {0x00c5, 0x8648},
-/* 467 */ {0x00d2, 0x8649},
-/* 468 */ {0x00dc, 0x864a},
-/* 469 */ {0x00e5, 0x864b},
-/* 470 */ {0x00eb, 0x864c},
-/* 471 */ {0x00f0, 0x864d},
-/* 472 */ {0x00f6, 0x864e},
-/* 473 */ {0x00fa, 0x864f},
-/* 474 */ {0x00ff, 0x8650},
-/* 475 */ {0x0060, 0x8657},
-/* 476 */ {0x0010, 0x8658},
-/* 477 */ {0x0018, 0x8659},
-/* 478 */ {0x0005, 0x865a},
-/* 479 */ {0x0018, 0x8660},
-/* 480 */ {0x0003, 0x8509},
-/* 481 */ {0x0011, 0x850a},
-/* 482 */ {0x0032, 0x850b},
-/* 483 */ {0x0010, 0x850c},
-/* 484 */ {0x0021, 0x850d},
-/* 485 */ {0x0001, 0x8500},
-/* 486 */ {0x0000, 0x8508},
-
-/* 487 */ {0x0012, 0x8608},
-/* 488 */ {0x002c, 0x8609},
-/* 489 */ {0x0002, 0x860a},
-/* 490 */ {0x0039, 0x860b},
-/* 491 */ {0x00d0, 0x860c},
-/* 492 */ {0x00f7, 0x860d},
-/* 493 */ {0x00ed, 0x860e},
-/* 494 */ {0x00db, 0x860f},
-/* 495 */ {0x0039, 0x8610},
-/* 496 */ {0x0012, 0x8657},
-/* 497 */ {0x0064, 0x8619},
+       {0x0020, 0x8112},
+
+       {0x000f, 0x8402},
+       {0x0000, 0x8403},
+
+       {0x0008, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x0009, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000a, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000b, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000c, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000d, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000e, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x0007, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000f, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+
+       {0x0018, 0x8660},
+       {0x0010, 0x8201},
+
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x0011, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+
+       {0x0000, 0x86b0},
+       {0x0034, 0x86b1},
+       {0x0000, 0x86b2},
+       {0x0049, 0x86b3},
+       {0x0000, 0x86b4},
+       {0x0000, 0x86b4},
+
+       {0x0012, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x0013, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+
+       {0x0001, 0x86b0},
+       {0x00aa, 0x86b1},
+       {0x0000, 0x86b2},
+       {0x00e4, 0x86b3},
+       {0x0000, 0x86b4},
+       {0x0000, 0x86b4},
+
+       {0x0018, 0x8660},
+
+       {0x0090, 0x8110},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0003, 0x8114},
+
+       {0x0080, 0x8804},
+       {0x0003, 0x8801},
+       {0x0012, 0x8800},
+       {0x0004, 0x8801},
+       {0x0005, 0x8800},
+       {0x0005, 0x8801},
+       {0x0000, 0x8800},
+       {0x0006, 0x8801},
+       {0x0000, 0x8800},
+       {0x0007, 0x8801},
+       {0x0000, 0x8800},
+       {0x0008, 0x8801},
+       {0x0005, 0x8800},
+       {0x000a, 0x8700},
+       {0x000e, 0x8801},
+       {0x0004, 0x8800},
+       {0x0005, 0x8801},
+       {0x0047, 0x8800},
+       {0x0006, 0x8801},
+       {0x0000, 0x8800},
+       {0x0007, 0x8801},
+       {0x00c0, 0x8800},
+       {0x0008, 0x8801},
+       {0x0003, 0x8800},
+       {0x0013, 0x8801},
+       {0x0001, 0x8800},
+       {0x0009, 0x8801},
+       {0x0000, 0x8800},
+       {0x000a, 0x8801},
+       {0x0000, 0x8800},
+       {0x000b, 0x8801},
+       {0x0000, 0x8800},
+       {0x000c, 0x8801},
+       {0x0000, 0x8800},
+       {0x000e, 0x8801},
+       {0x0004, 0x8800},
+       {0x000f, 0x8801},
+       {0x0000, 0x8800},
+       {0x0010, 0x8801},
+       {0x0006, 0x8800},
+       {0x0011, 0x8801},
+       {0x0006, 0x8800},
+       {0x0012, 0x8801},
+       {0x0000, 0x8800},
+       {0x0013, 0x8801},
+       {0x0001, 0x8800},
+
+       {0x000a, 0x8700},
+       {0x0000, 0x8702},
+       {0x0000, 0x8703},
+       {0x00c2, 0x8704},
+       {0x0001, 0x870c},
+
+       {0x0044, 0x8600},
+       {0x0002, 0x8606},
+       {0x0064, 0x8607},
+       {0x003a, 0x8601},
+       {0x0008, 0x8602},
+       {0x0044, 0x8600},
+       {0x0018, 0x8617},
+       {0x0008, 0x8618},
+       {0x00a1, 0x8656},
+       {0x0004, 0x865b},
+       {0x0002, 0x865c},
+       {0x0058, 0x865d},
+       {0x0048, 0x865e},
+       {0x0012, 0x8608},
+       {0x002c, 0x8609},
+       {0x0002, 0x860a},
+       {0x002c, 0x860b},
+       {0x00db, 0x860c},
+       {0x00f9, 0x860d},
+       {0x00f1, 0x860e},
+       {0x00e3, 0x860f},
+       {0x002c, 0x8610},
+       {0x006c, 0x8651},
+       {0x0041, 0x8652},
+       {0x0059, 0x8653},
+       {0x0040, 0x8654},
+       {0x00fa, 0x8611},
+       {0x00ff, 0x8612},
+       {0x00f8, 0x8613},
+       {0x0000, 0x8614},
+       {0x0001, 0x863f},
+       {0x0000, 0x8640},
+       {0x0026, 0x8641},
+       {0x0045, 0x8642},
+       {0x0060, 0x8643},
+       {0x0075, 0x8644},
+       {0x0088, 0x8645},
+       {0x009b, 0x8646},
+       {0x00b0, 0x8647},
+       {0x00c5, 0x8648},
+       {0x00d2, 0x8649},
+       {0x00dc, 0x864a},
+       {0x00e5, 0x864b},
+       {0x00eb, 0x864c},
+       {0x00f0, 0x864d},
+       {0x00f6, 0x864e},
+       {0x00fa, 0x864f},
+       {0x00ff, 0x8650},
+       {0x0060, 0x8657},
+       {0x0010, 0x8658},
+       {0x0018, 0x8659},
+       {0x0005, 0x865a},
+       {0x0018, 0x8660},
+       {0x0003, 0x8509},
+       {0x0011, 0x850a},
+       {0x0032, 0x850b},
+       {0x0010, 0x850c},
+       {0x0021, 0x850d},
+       {0x0001, 0x8500},
+       {0x0000, 0x8508},
+       {0x0012, 0x8608},
+       {0x002c, 0x8609},
+       {0x0002, 0x860a},
+       {0x0039, 0x860b},
+       {0x00d0, 0x860c},
+       {0x00f7, 0x860d},
+       {0x00ed, 0x860e},
+       {0x00db, 0x860f},
+       {0x0039, 0x8610},
+       {0x0012, 0x8657},
+       {0x000c, 0x8619},
+       {0x0004, 0x861a},
+       {0x00a1, 0x8656},
+       {0x00c8, 0x8615},
+       {0x0032, 0x8616},
+
+       {0x0030, 0x8112},
+       {0x0020, 0x8112},
+       {0x0020, 0x8112},
+       {0x000f, 0x8402},
+       {0x0000, 0x8403},
+
+       {0x0090, 0x8110},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0003, 0x8114},
+       {0x0080, 0x8804},
+
+       {0x0003, 0x8801},
+       {0x0012, 0x8800},
+       {0x0004, 0x8801},
+       {0x0005, 0x8800},
+       {0x0005, 0x8801},
+       {0x0047, 0x8800},
+       {0x0006, 0x8801},
+       {0x0000, 0x8800},
+       {0x0007, 0x8801},
+       {0x00c0, 0x8800},
+       {0x0008, 0x8801},
+       {0x0003, 0x8800},
+       {0x000a, 0x8700},
+       {0x000e, 0x8801},
+       {0x0004, 0x8800},
+       {0x0005, 0x8801},
+       {0x0047, 0x8800},
+       {0x0006, 0x8801},
+       {0x0000, 0x8800},
+       {0x0007, 0x8801},
+       {0x00c0, 0x8800},
+       {0x0008, 0x8801},
+       {0x0003, 0x8800},
+       {0x0013, 0x8801},
+       {0x0001, 0x8800},
+       {0x0009, 0x8801},
+       {0x0000, 0x8800},
+       {0x000a, 0x8801},
+       {0x0000, 0x8800},
+       {0x000b, 0x8801},
+       {0x0000, 0x8800},
+       {0x000c, 0x8801},
+       {0x0000, 0x8800},
+       {0x000e, 0x8801},
+       {0x0004, 0x8800},
+       {0x000f, 0x8801},
+       {0x0000, 0x8800},
+       {0x0010, 0x8801},
+       {0x0006, 0x8800},
+       {0x0011, 0x8801},
+       {0x0006, 0x8800},
+       {0x0012, 0x8801},
+       {0x0000, 0x8800},
+       {0x0013, 0x8801},
+       {0x0001, 0x8800},
+       {0x000a, 0x8700},
+       {0x0000, 0x8702},
+       {0x0000, 0x8703},
+       {0x00c2, 0x8704},
+       {0x0001, 0x870c},
+       {0x0044, 0x8600},
+       {0x0002, 0x8606},
+       {0x0064, 0x8607},
+       {0x003a, 0x8601},
+       {0x0008, 0x8602},
+       {0x0044, 0x8600},
+       {0x0018, 0x8617},
+       {0x0008, 0x8618},
+       {0x00a1, 0x8656},
+       {0x0004, 0x865b},
+       {0x0002, 0x865c},
+       {0x0058, 0x865d},
+       {0x0048, 0x865e},
+       {0x0012, 0x8608},
+       {0x002c, 0x8609},
+       {0x0002, 0x860a},
+       {0x002c, 0x860b},
+       {0x00db, 0x860c},
+       {0x00f9, 0x860d},
+       {0x00f1, 0x860e},
+       {0x00e3, 0x860f},
+       {0x002c, 0x8610},
+       {0x006c, 0x8651},
+       {0x0041, 0x8652},
+       {0x0059, 0x8653},
+       {0x0040, 0x8654},
+       {0x00fa, 0x8611},
+       {0x00ff, 0x8612},
+       {0x00f8, 0x8613},
+       {0x0000, 0x8614},
+       {0x0001, 0x863f},
+       {0x0000, 0x8640},
+       {0x0026, 0x8641},
+       {0x0045, 0x8642},
+       {0x0060, 0x8643},
+       {0x0075, 0x8644},
+       {0x0088, 0x8645},
+       {0x009b, 0x8646},
+       {0x00b0, 0x8647},
+       {0x00c5, 0x8648},
+       {0x00d2, 0x8649},
+       {0x00dc, 0x864a},
+       {0x00e5, 0x864b},
+       {0x00eb, 0x864c},
+       {0x00f0, 0x864d},
+       {0x00f6, 0x864e},
+       {0x00fa, 0x864f},
+       {0x00ff, 0x8650},
+       {0x0060, 0x8657},
+       {0x0010, 0x8658},
+       {0x0018, 0x8659},
+       {0x0005, 0x865a},
+       {0x0018, 0x8660},
+       {0x0003, 0x8509},
+       {0x0011, 0x850a},
+       {0x0032, 0x850b},
+       {0x0010, 0x850c},
+       {0x0021, 0x850d},
+       {0x0001, 0x8500},
+       {0x0000, 0x8508},
+
+       {0x0012, 0x8608},
+       {0x002c, 0x8609},
+       {0x0002, 0x860a},
+       {0x0039, 0x860b},
+       {0x00d0, 0x860c},
+       {0x00f7, 0x860d},
+       {0x00ed, 0x860e},
+       {0x00db, 0x860f},
+       {0x0039, 0x8610},
+       {0x0012, 0x8657},
+       {0x0064, 0x8619},
 
 /* This line starts it all, it is not needed here */
 /* since it has been build into the driver */
 /* jfm: don't start now */
-/* 590  *  {0x0030, 0x8112}, */
+/*     {0x0030, 0x8112}, */
        {}
 };
 
@@ -1109,14 +1023,14 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x0008, 0x8200},       /* Clear register */
        {0x0000, 0x870b},       /* Reset CTL3 */
        {0x0020, 0x8112},       /* Video Drop packet enable */
-       {0x0003, 0x8111},  /* Soft Reset compression, memory, TG & CDSP */
+       {0x0003, 0x8111},       /* Soft Reset compression, memory, TG & CDSP */
        {0x0000, 0x8110},       /* Disable everything */
        {0x0000, 0x8114},       /* Software GPIO output data */
        {0x0000, 0x8114},
 
        {0x0003, 0x8111},
        {0x0000, 0x8111},
-       {0x0090, 0x8110},  /* Enable: SSI output, External 2X clock output */
+       {0x0090, 0x8110},    /* Enable: SSI output, External 2X clock output */
        {0x0020, 0x8112},
        {0x0000, 0x8114},
        {0x0001, 0x8114},
@@ -1129,191 +1043,143 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x00ba, 0x8804},       /* SSI Slave address */
        {0x0010, 0x8802},       /* 93.75kHz SSI Clock Two DataByte */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},       /* Will write 2 bytes (DATA1+DATA2) */
        {0x0020, 0x8801},       /* Register address for SSI read/write */
        {0x0044, 0x8805},       /* DATA2 */
        {0x0004, 0x8800},       /* DATA1 -> write triggered */
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0009, 0x8801},
        {0x0042, 0x8805},
        {0x0001, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x003c, 0x8801},
        {0x0001, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0001, 0x8801},
        {0x000a, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0002, 0x8801},
        {0x0000, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0003, 0x8801},
        {0x0027, 0x8805},
        {0x0001, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0004, 0x8801},
        {0x0065, 0x8805},
        {0x0001, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0005, 0x8801},
        {0x0003, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0006, 0x8801},
        {0x001c, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0007, 0x8801},
        {0x002a, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x000e, 0x8801},
        {0x0000, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0028, 0x8801},
        {0x002e, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0039, 0x8801},
        {0x0013, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x003b, 0x8801},
        {0x000c, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0035, 0x8801},
        {0x0028, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0009, 0x8801},
        {0x0042, 0x8805},
        {0x0001, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
        {0x0050, 0x8703},
        {0x0002, 0x8704},       /* External input CKIx1 */
        {0x0001, 0x870c},       /* Select CKOx2 output */
        {0x009a, 0x8600},       /* Line memory Read Counter (L) */
-       {0x0001, 0x8606},  /* 1 Line memory Read Counter (H) Result: (d)410 */
+       {0x0001, 0x8606},    /* 1 Line memory Read Counter (H) Result: (d)410 */
        {0x0023, 0x8601},
        {0x0010, 0x8602},
        {0x000a, 0x8603},
-       {0x009A, 0x8600},
+       {0x009a, 0x8600},
        {0x0001, 0x865b},       /* 1 Horizontal Offset for Valid Pixel(L) */
        {0x0003, 0x865c},       /* Vertical offset for valid lines (L) */
        {0x0058, 0x865d},       /* Horizontal valid pixels window (L) */
@@ -1329,7 +1195,7 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x0005, 0x860a},       /* ... */
        {0x0025, 0x860b},
        {0x00e1, 0x860c},
-       {0x00fa, 0x860D},
+       {0x00fa, 0x860d},
        {0x00f4, 0x860e},
        {0x00e8, 0x860f},
        {0x0025, 0x8610},       /* A33 Coef. */
@@ -1344,11 +1210,12 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x0040, 0x8654},       /* Gb gain for white balance (L) */
        {0x0001, 0x863f},       /* Enable fixed gamma correction */
 
-       {0x00a1, 0x8656},       /* Size - Window1: 256x256, Window2: 128x128 */
-       /* UV division: UV no change, Enable New edge enhancement */
+       {0x00a1, 0x8656},       /* Size - Window1: 256x256, Window2: 128x128,
+                                * UV division: UV no change,
+                                * Enable New edge enhancement */
        {0x0018, 0x8657},       /* Edge gain high threshold */
        {0x0020, 0x8658},       /* Edge gain low threshold */
-       {0x000A, 0x8659},       /* Edge bandwidth high threshold */
+       {0x000a, 0x8659},       /* Edge bandwidth high threshold */
        {0x0005, 0x865a},       /* Edge bandwidth low threshold */
        {0x0064, 0x8607},       /* UV filter enable */
 
@@ -1384,29 +1251,20 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x0000, 0x86b4},
        {0x001e, 0x8660},
 
-       /* READ { 0, 0x0000, 0x8608 } ->
-               0000: 13  */
-       /* READ { 0, 0x0000, 0x8609 } ->
-               0000: 28  */
-       /* READ { 0, 0x0000, 0x8610 } ->
-               0000: 05  */
-       /* READ { 0, 0x0000, 0x8611 } ->
-               0000: 25  */
-       /* READ { 0, 0x0000, 0x8612 } ->
-               0000: e1  */
-       /* READ { 0, 0x0000, 0x8613 } ->
-               0000: fa  */
-       /* READ { 0, 0x0000, 0x8614 } ->
-               0000: f4  */
-       /* READ { 0, 0x0000, 0x8615 } ->
-               0000: e8  */
-       /* READ { 0, 0x0000, 0x8616 } ->
-               0000: 25  */
+       /* READ { 0x0000, 0x8608 } -> 0000: 13  */
+       /* READ { 0x0000, 0x8609 } -> 0000: 28  */
+       /* READ { 0x0000, 0x8610 } -> 0000: 05  */
+       /* READ { 0x0000, 0x8611 } -> 0000: 25  */
+       /* READ { 0x0000, 0x8612 } -> 0000: e1  */
+       /* READ { 0x0000, 0x8613 } -> 0000: fa  */
+       /* READ { 0x0000, 0x8614 } -> 0000: f4  */
+       /* READ { 0x0000, 0x8615 } -> 0000: e8  */
+       /* READ { 0x0000, 0x8616 } -> 0000: 25  */
        {}
 };
 
 static int reg_write(struct usb_device *dev,
-                       __u16 index, __u16 value)
+                       u16 index, u16 value)
 {
        int ret;
 
@@ -1425,7 +1283,7 @@ static int reg_write(struct usb_device *dev,
 /* read 1 byte */
 /* returns: negative is error, pos or zero is data */
 static int reg_read(struct gspca_dev *gspca_dev,
-                       __u16 index)    /* wIndex */
+                       u16 index)      /* wIndex */
 {
        int ret;
 
@@ -1447,16 +1305,16 @@ static int reg_read(struct gspca_dev *gspca_dev,
 }
 
 static int write_vector(struct gspca_dev *gspca_dev,
-                       const u16 data[][2])
+                       const u16 (*data)[2])
 {
        struct usb_device *dev = gspca_dev->dev;
-       int ret, i = 0;
+       int ret;
 
-       while (data[i][1] != 0) {
-               ret = reg_write(dev, data[i][1], data[i][0]);
+       while ((*data)[1] != 0) {
+               ret = reg_write(dev, (*data)[1], (*data)[0]);
                if (ret < 0)
                        return ret;
-               i++;
+               data++;
        }
        return 0;
 }
@@ -1468,6 +1326,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam;
        int data1, data2;
+       const u16 (*init_data)[2];
+       static const u16 (*(init_data_tb[]))[2] = {
+               spca508_vista_init_data,        /* CreativeVista 0 */
+               spca508_sightcam_init_data,     /* HamaUSBSightcam 1 */
+               spca508_sightcam2_init_data,    /* HamaUSBSightcam2 2 */
+               spca508cs110_init_data,         /* IntelEasyPCCamera 3 */
+               spca508cs110_init_data,         /* MicroInnovationIC200 4 */
+               spca508_init_data,              /* ViewQuestVQ110 5 */
+       };
 
        /* Read from global register the USB product and vendor IDs, just to
         * prove that we can communicate with the device.  This works, which
@@ -1491,37 +1358,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->subtype = id->driver_info;
        sd->brightness = BRIGHTNESS_DEF;
 
-       switch (sd->subtype) {
-       case ViewQuestVQ110:
-               if (write_vector(gspca_dev, spca508_init_data))
-                       return -1;
-               break;
-       default:
-/*     case MicroInnovationIC200: */
-/*     case IntelEasyPCCamera: */
-               if (write_vector(gspca_dev, spca508cs110_init_data))
-                       return -1;
-               break;
-       case HamaUSBSightcam:
-               if (write_vector(gspca_dev, spca508_sightcam_init_data))
-                       return -1;
-               break;
-       case HamaUSBSightcam2:
-               if (write_vector(gspca_dev, spca508_sightcam2_init_data))
-                       return -1;
-               break;
-       case CreativeVista:
-               if (write_vector(gspca_dev, spca508_vista_init_data))
-                       return -1;
-               break;
-       }
-       return 0;                       /* success */
+       init_data = init_data_tb[sd->subtype];
+       return write_vector(gspca_dev, init_data);
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-/*     write_vector(gspca_dev, spca508_open_data); */
        return 0;
 }
 
@@ -1529,7 +1372,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        int mode;
 
-       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+       mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
        reg_write(gspca_dev->dev, 0x8500, mode);
        switch (mode) {
        case 0:
@@ -1554,7 +1397,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
-                       __u8 *data,                     /* isoc packet */
+                       u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
        switch (data[0]) {
@@ -1567,7 +1410,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                data, len);
                break;
        case 0xff:                      /* drop */
-/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
                break;
        default:
                data += 1;
@@ -1581,7 +1423,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 brightness = sd->brightness;
+       u8 brightness = sd->brightness;
 
        /* MX seem contrast */
        reg_write(gspca_dev->dev, 0x8651, brightness);
index c99c5e34e211d6ada81910d0d0b5bf981b11ac08..27e82b35f3e7f15be7a3ea60337b58519d85cd44 100644 (file)
@@ -34,8 +34,8 @@ struct sd {
 
        __u16 exposure;                 /* rev12a only */
 #define EXPOSURE_MIN 1
-#define EXPOSURE_DEF 200
-#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
+#define EXPOSURE_DEF 700               /* == 10 fps */
+#define EXPOSURE_MAX (2047 + 325)      /* see setexposure */
 
        __u8 contrast;                  /* rev72a only */
 #define CONTRAST_MIN 0x00
@@ -48,9 +48,9 @@ struct sd {
 #define BRIGHTNESS_MAX 0x3f
 
        __u8 white;
-#define WHITE_MIN 1
-#define WHITE_DEF 0x40
-#define WHITE_MAX 0x7f
+#define HUE_MIN 1
+#define HUE_DEF 0x40
+#define HUE_MAX 0x7f
 
        __u8 autogain;
 #define AUTOGAIN_MIN 0
@@ -58,9 +58,9 @@ struct sd {
 #define AUTOGAIN_MAX 1
 
        __u8 gain;                      /* rev12a only */
-#define GAIN_MIN 0x0
-#define GAIN_DEF 0x24
-#define GAIN_MAX 0x24
+#define GAIN_MIN 0
+#define GAIN_DEF 63
+#define GAIN_MAX 255
 
 #define EXPO12A_DEF 3
        __u8 expo12a;           /* expo/gain? for rev 12a */
@@ -461,7 +461,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
-       sd->white = WHITE_DEF;
+       sd->white = HUE_DEF;
        sd->exposure = EXPOSURE_DEF;
        sd->autogain = AUTOGAIN_DEF;
        sd->gain = GAIN_DEF;
@@ -549,8 +549,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 static void setexposure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int expo;
-       int clock_divider;
+       int i, expo = 0;
 
        /* Register 0x8309 controls exposure for the spca561,
           the basic exposure setting goes from 1-2047, where 1 is completely
@@ -564,16 +563,22 @@ static void setexposure(struct gspca_dev *gspca_dev)
           configure a divider for the base framerate which us used at the
           exposure setting of 1-300. These bits configure the base framerate
           according to the following formula: fps = 60 / (value + 2) */
-       if (sd->exposure < 2048) {
-               expo = sd->exposure;
-               clock_divider = 0;
-       } else {
-               /* Add 900 to make the 0 setting of the second part of the
-                  exposure equal to the 2047 setting of the first part. */
-               expo = (sd->exposure - 2048) + 900;
-               clock_divider = 3;
+
+       /* We choose to use the high bits setting the fixed framerate divisor
+          asap, as setting high basic exposure setting without the fixed
+          divider in combination with high gains makes the cam stop */
+       int table[] =  { 0, 450, 550, 625, EXPOSURE_MAX };
+
+       for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
+               if (sd->exposure <= table[i + 1]) {
+                       expo  = sd->exposure - table[i];
+                       if (i)
+                               expo += 300;
+                       expo |= i << 11;
+                       break;
+               }
        }
-       expo |= clock_divider << 11;
+
        gspca_dev->usb_buf[0] = expo;
        gspca_dev->usb_buf[1] = expo >> 8;
        reg_w_buf(gspca_dev, 0x8309, 2);
@@ -584,7 +589,16 @@ static void setgain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       gspca_dev->usb_buf[0] = sd->gain;
+       /* gain reg low 6 bits  0-63 gain, bit 6 and 7, both double the
+          sensitivity when set, so 31 + one of them set == 63, and 15
+          with both of them set == 63 */
+       if (sd->gain < 64)
+               gspca_dev->usb_buf[0] = sd->gain;
+       else if (sd->gain < 128)
+               gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40;
+       else
+               gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xC0;
+
        gspca_dev->usb_buf[1] = 0;
        reg_w_buf(gspca_dev, 0x8335, 2);
 }
@@ -629,8 +643,7 @@ static int sd_start_12a(struct gspca_dev *gspca_dev)
        reg_w_buf(gspca_dev, 0x8391, 8);
        reg_w_buf(gspca_dev, 0x8390, 8);
        setwhite(gspca_dev);
-       setautogain(gspca_dev);
-/*     setgain(gspca_dev);             */
+       setgain(gspca_dev);
        setexposure(gspca_dev);
        return 0;
 }
@@ -762,18 +775,6 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                        i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
                }
                break;
-       case Rev012A:
-               reg_r(gspca_dev, 0x8330, 2);
-               if (gspca_dev->usb_buf[1] > 0x08) {
-                       gspca_dev->usb_buf[0] = ++sd->expo12a;
-                       gspca_dev->usb_buf[1] = 0;
-                       reg_w_buf(gspca_dev, 0x8339, 2);
-               } else if (gspca_dev->usb_buf[1] < 0x02) {
-                       gspca_dev->usb_buf[0] = --sd->expo12a;
-                       gspca_dev->usb_buf[1] = 0;
-                       reg_w_buf(gspca_dev, 0x8339, 2);
-               }
-               break;
        }
 }
 
@@ -928,13 +929,13 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
 static struct ctrl sd_ctrls_12a[] = {
        {
            {
-               .id = V4L2_CID_DO_WHITE_BALANCE,
+               .id = V4L2_CID_HUE,
                .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "White Balance",
-               .minimum = WHITE_MIN,
-               .maximum = WHITE_MAX,
+               .name = "Hue",
+               .minimum = HUE_MIN,
+               .maximum = HUE_MAX,
                .step = 1,
-               .default_value = WHITE_DEF,
+               .default_value = HUE_DEF,
            },
            .set = sd_setwhite,
            .get = sd_getwhite,
@@ -952,19 +953,6 @@ static struct ctrl sd_ctrls_12a[] = {
            .set = sd_setexposure,
            .get = sd_getexposure,
        },
-       {
-           {
-               .id = V4L2_CID_AUTOGAIN,
-               .type = V4L2_CTRL_TYPE_BOOLEAN,
-               .name = "Auto Gain",
-               .minimum = AUTOGAIN_MIN,
-               .maximum = AUTOGAIN_MAX,
-               .step = 1,
-               .default_value = AUTOGAIN_DEF,
-           },
-           .set = sd_setautogain,
-           .get = sd_getautogain,
-       },
        {
            {
                .id = V4L2_CID_GAIN,
@@ -983,13 +971,13 @@ static struct ctrl sd_ctrls_12a[] = {
 static struct ctrl sd_ctrls_72a[] = {
        {
            {
-               .id = V4L2_CID_DO_WHITE_BALANCE,
+               .id = V4L2_CID_HUE,
                .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "White Balance",
-               .minimum = WHITE_MIN,
-               .maximum = WHITE_MAX,
+               .name = "Hue",
+               .minimum = HUE_MIN,
+               .maximum = HUE_MAX,
                .step = 1,
-               .default_value = WHITE_DEF,
+               .default_value = HUE_DEF,
            },
            .set = sd_setwhite,
            .get = sd_getwhite,
@@ -1046,7 +1034,6 @@ static const struct sd_desc sd_desc_12a = {
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
-/*     .dq_callback = do_autogain,      * fixme */
 };
 static const struct sd_desc sd_desc_72a = {
        .name = MODULE_NAME,
index 2e1cdf068fda896043f2222622ac17a3798a982f..715a68f0156eb6128fa4ab5f7cb44ade79edf6d5 100644 (file)
@@ -309,6 +309,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct sd *dev = (struct sd *) gspca_dev;
 
        /* We don't use the buffer gspca allocates so make it small. */
+       cam->bulk = 1;
        cam->bulk_size = 64;
 
        INIT_WORK(&dev->work_struct, sq905_dostream);
index 0bcb74a1b143425592ea5957dc6ae826bb2fa421..9168925054328229f0c2ff7dad6d9a53381d2383 100644 (file)
@@ -206,6 +206,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->nmodes = 1;
        /* We don't use the buffer gspca allocates so make it small. */
        cam->bulk_size = 32;
+       cam->bulk = 1;
        INIT_WORK(&dev->work_struct, sq905c_dostream);
        return 0;
 }
index 9dff2e65b116680b15b0d0e04383ce03918f9b12..e573c3406324bf7f5a71a2da4804e4cd73b540c9 100644 (file)
@@ -293,8 +293,6 @@ static void stv06xx_stopN(struct gspca_dev *gspca_dev)
                goto out;
 
        err = sd->sensor->stop(sd);
-       if (err < 0)
-               goto out;
 
 out:
        if (err < 0)
index 69c77c932fc027b16e2d1d0d0d61962233f44b9c..11a0c002f5dcb579dc2047d8ec5b024a7b1da253 100644 (file)
@@ -80,12 +80,26 @@ static const struct ctrl vv6410_ctrl[] = {
                        .minimum        = 0,
                        .maximum        = 15,
                        .step           = 1,
-                       .default_value  = 0
+                       .default_value  = 10
                },
                .set = vv6410_set_analog_gain,
                .get = vv6410_get_analog_gain
+       },
+#define EXPOSURE_IDX 3
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "exposure",
+                       .minimum        = 0,
+                       .maximum        = 32768,
+                       .step           = 1,
+                       .default_value  = 20000
+               },
+               .set = vv6410_set_exposure,
+               .get = vv6410_get_exposure
        }
-};
+       };
 
 static int vv6410_probe(struct sd *sd)
 {
@@ -121,6 +135,7 @@ static int vv6410_probe(struct sd *sd)
 static int vv6410_init(struct sd *sd)
 {
        int err = 0, i;
+       s32 *sensor_settings = sd->sensor_priv;
 
        for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
                /* if NULL then len contains single value */
@@ -142,6 +157,16 @@ static int vv6410_init(struct sd *sd)
 
        err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
                                         ARRAY_SIZE(vv6410_sensor_init));
+       if (err < 0)
+               return err;
+
+       err = vv6410_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = vv6410_set_analog_gain(&sd->gspca_dev,
+                                     sensor_settings[GAIN_IDX]);
 
        return (err < 0) ? err : 0;
 }
@@ -318,3 +343,50 @@ static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
 
        return (err < 0) ? err : 0;
 }
+
+static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[EXPOSURE_IDX];
+
+       PDEBUG(D_V4L2, "Read exposure %d", *val);
+
+       return 0;
+}
+
+static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+       unsigned int fine, coarse;
+
+       sensor_settings[EXPOSURE_IDX] = val;
+
+       val = (val * val >> 14) + val / 4;
+
+       fine = val % VV6410_CIF_LINELENGTH;
+       coarse = min(512, val / VV6410_CIF_LINELENGTH);
+
+       PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d",
+              coarse, fine);
+
+       err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8);
+       if (err < 0)
+               goto out;
+
+       err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff);
+       if (err < 0)
+               goto out;
+
+       err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8);
+       if (err < 0)
+               goto out;
+
+       err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff);
+
+out:
+       return err;
+}
index 95ac55891bd427c9a02b9252f07b5c906359dca6..487d40555343f7581148c4656829f282d88bff0b 100644 (file)
 #define VV6410_SUBSAMPLE               0x01
 #define VV6410_CROP_TO_QVGA            0x02
 
+#define VV6410_CIF_LINELENGTH          415
+
 static int vv6410_probe(struct sd *sd);
 static int vv6410_start(struct sd *sd);
 static int vv6410_init(struct sd *sd);
@@ -187,6 +189,8 @@ static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
 static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val);
 static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
 
 const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
        .name = "ST VV6410",
@@ -242,12 +246,6 @@ static const u8 vv6410_sensor_init[][2] = {
        /* Pre-clock generator divide off */
        {VV6410_DATAFORMAT,     BIT(7) | BIT(0)},
 
-       /* Exposure registers */
-       {VV6410_FINEH,          VV6410_FINE_EXPOSURE >> 8},
-       {VV6410_FINEL,          VV6410_FINE_EXPOSURE & 0xff},
-       {VV6410_COARSEH,        VV6410_COARSE_EXPOSURE >> 8},
-       {VV6410_COARSEL,        VV6410_COARSE_EXPOSURE & 0xff},
-       {VV6410_ANALOGGAIN,     0xf0 | VV6410_DEFAULT_GAIN},
        {VV6410_CLKDIV,         VV6410_CLK_DIV_2},
 
        /* System registers */
index c2b8c10c075add3bc79f5e83c4a36b2fd8cd5125..9623f294bdac1aada92418a7b58f0cbf80a21819 100644 (file)
@@ -32,9 +32,6 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       __u8 packet[ISO_MAX_SIZE + 128];
-                               /* !! no more than 128 ff in an ISO packet */
-
        unsigned char brightness;
        unsigned char contrast;
        unsigned char colors;
@@ -1103,7 +1100,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i, sof = 0;
-       unsigned char *s, *d;
        static unsigned char ffd9[] = {0xff, 0xd9};
 
 /* frames are jpeg 4.1.1 without 0xff escape */
@@ -1177,22 +1173,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        }
 
        /* add 0x00 after 0xff */
-       for (i = len; --i >= 0; )
-               if (data[i] == 0xff)
-                       break;
-       if (i < 0) {                    /* no 0xff */
-               gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
-               return;
-       }
-       s = data;
-       d = sd->packet;
-       for (i = 0; i < len; i++) {
-               *d++ = *s++;
-               if (s[-1] == 0xff)
-                       *d++ = 0x00;
-       }
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                       sd->packet, d - sd->packet);
+       i = 0;
+       do {
+               if (data[i] == 0xff) {
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                       data, i + 1);
+                       len -= i;
+                       data += i;
+                       *data = 0x00;
+                       i = 0;
+               }
+               i++;
+       } while (i < len);
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
 static void setbrightness(struct gspca_dev *gspca_dev)
index f63e37e2e4fdd3c4031b69fd12c7bcd849b16978..404214b8cd2bed98d22e036f6d71bd8b4672add9 100644 (file)
@@ -697,7 +697,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                return -EINVAL;
        }
 
-       if (sd->sensor != SENSOR_OTHER) {
+       if (sd->sensor == SENSOR_OM6802) {
                reg_w_buf(gspca_dev, n1, sizeof n1);
                i = 5;
                while (--i >= 0) {
index e4e933c400bccd49a7def89c29d4a6038b20e880..26dd155efcc32d39be0b67619a925c0acb856af7 100644 (file)
@@ -42,7 +42,7 @@ struct sd {
        char bridge;
 #define BRIDGE_VC0321 0
 #define BRIDGE_VC0323 1
-       char sensor;
+       u8 sensor;
 #define SENSOR_HV7131R 0
 #define SENSOR_MI0360 1
 #define SENSOR_MI1310_SOC 2
@@ -159,17 +159,17 @@ static const struct v4l2_pix_format vc0323_mode[] = {
                .priv = 2},
 };
 static const struct v4l2_pix_format bi_mode[] = {
-       {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+       {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 2},
-       {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+       {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
                .bytesperline = 640,
                .sizeimage = 640 * 480 * 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1},
-       {1280, 1024, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+       {1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
                .bytesperline = 1280,
                .sizeimage = 1280 * 1024 * 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
@@ -2453,6 +2453,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct usb_device *dev = gspca_dev->dev;
        struct cam *cam;
        int sensor;
+       static u8 npkt[] = {    /* number of packets per ISOC message */
+               64,             /* HV7131R 0 */
+               32,             /* MI0360 1 */
+               32,             /* MI1310_SOC 2 */
+               64,             /* MI1320 3 */
+               128,            /* MI1320_SOC 4 */
+               32,             /* OV7660 5 */
+               64,             /* OV7670 6 */
+               128,            /* PO1200 7 */
+               128,            /* PO3130NC 8 */
+       };
 
        cam = &gspca_dev->cam;
        sd->bridge = id->driver_info;
@@ -2508,6 +2519,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
                case SENSOR_MI1320_SOC:
                        cam->cam_mode = bi_mode;
                        cam->nmodes = ARRAY_SIZE(bi_mode);
+                       cam->input_flags = V4L2_IN_ST_VFLIP |
+                                          V4L2_IN_ST_HFLIP;
                        break;
                default:
                        cam->cam_mode = vc0323_mode;
@@ -2515,6 +2528,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        break;
                }
        }
+       cam->npkt = npkt[sd->sensor];
 
        sd->hflip = HFLIP_DEF;
        sd->vflip = VFLIP_DEF;
index 4fe01d8b6c87e542d6e4655d55c4ab4567fc369f..08422d315e68023a10c94570b192dffa8e8c2503 100644 (file)
@@ -6307,7 +6307,7 @@ static __u16 i2c_read(struct gspca_dev *gspca_dev,
        retbyte = reg_r_i(gspca_dev, 0x0091);           /* read status */
        retval = reg_r_i(gspca_dev, 0x0095);            /* read Lowbyte */
        retval |= reg_r_i(gspca_dev, 0x0096) << 8;      /* read Hightbyte */
-       PDEBUG(D_USBO, "i2c r [%02x] -> %04x (%02x)",
+       PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)",
                        reg, retval, retbyte);
        return retval;
 }
@@ -6868,7 +6868,6 @@ static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
        {0x8001, 0x13},
        {0x8000, 0x14},         /* CS2102K */
        {0x8400, 0x15},         /* TAS5130K */
-       {0x4001, 0x16},         /* ADCM2700 */
 };
 
 static int vga_3wr_probe(struct gspca_dev *gspca_dev)
@@ -6904,12 +6903,15 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        retword |= reg_r(gspca_dev, 0x000a);
        PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", retword);
        reg_r(gspca_dev, 0x0010);
-       /* this is tested only once anyway */
-       for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
-               if (chipset_revision_sensor[i].revision == retword) {
-                       sd->chip_revision = retword;
-                       send_unknown(dev, SENSOR_PB0330);
-                       return chipset_revision_sensor[i].internal_sensor_id;
+       /* value 0x4001 is meaningless */
+       if (retword != 0x4001) {
+               for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
+                       if (chipset_revision_sensor[i].revision == retword) {
+                               sd->chip_revision = retword;
+                               send_unknown(dev, SENSOR_PB0330);
+                               return chipset_revision_sensor[i]
+                                                       .internal_sensor_id;
+                       }
                }
        }
 
@@ -6980,12 +6982,12 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        reg_w(dev, 0x01, 0x0001);
        reg_w(dev, 0x03, 0x0012);
        reg_w(dev, 0x01, 0x0012);
-       reg_w(dev, 0x05, 0x0001);
+       reg_w(dev, 0x05, 0x0012);
        reg_w(dev, 0xd3, 0x008b);
        retword = i2c_read(gspca_dev, 0x01);
        if (retword != 0) {
                PDEBUG(D_PROBE, "probe 3wr vga type 0a ? ret: %04x", retword);
-               return retword;
+               return 0x16;                    /* adcm2700 (6100/6200) */
        }
        return -1;
 }
index 8e1463ee1b6420c0e9e652850a05293900bdf150..71c211402eb5e3bd9c6759904299a80fa1cb2544 100644 (file)
@@ -224,7 +224,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
        DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
 
-       if (i->index < 0 || i->index >= HEXIUM_INPUTS)
+       if (i->index >= HEXIUM_INPUTS)
                return -EINVAL;
 
        memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
index 2bc39f62845527dda7391c253d2aa6c0d29b148a..39d65ca41c627026a83ebc899a84fdb08d71b438 100644 (file)
@@ -325,7 +325,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
        DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
 
-       if (i->index < 0 || i->index >= HEXIUM_INPUTS)
+       if (i->index >= HEXIUM_INPUTS)
                return -EINVAL;
 
        memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
index 092c7da0f37a7a534351536cd2f57ee15b01a4ab..86f2fefe1edf28a9db5b93b9c13af6696dbf8e5d 100644 (file)
@@ -74,7 +74,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
        int start, range, toggle, dev, code, ircode;
 
        /* poll IR chip */
-       if (size != i2c_master_recv(&ir->c,buf,size))
+       if (size != i2c_master_recv(ir->c, buf, size))
                return -EIO;
 
        /* split rc5 data block ... */
@@ -137,7 +137,7 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -151,7 +151,7 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -171,7 +171,7 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char buf[4];
 
        /* poll IR chip */
-       if (4 != i2c_master_recv(&ir->c,buf,4)) {
+       if (4 != i2c_master_recv(ir->c, buf, 4)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -195,7 +195,7 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -222,12 +222,12 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
                                     u32 *ir_key, u32 *ir_raw)
 {
        unsigned char subaddr, key, keygroup;
-       struct i2c_msg msg[] = { { .addr = ir->c.addr, .flags = 0,
+       struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0,
                                   .buf = &subaddr, .len = 1},
-                                { .addr = ir->c.addr, .flags = I2C_M_RD,
+                                { .addr = ir->c->addr, .flags = I2C_M_RD,
                                  .buf = &key, .len = 1} };
        subaddr = 0x0d;
-       if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+       if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
                dprintk(1, "read error\n");
                return -EIO;
        }
@@ -237,7 +237,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
 
        subaddr = 0x0b;
        msg[1].buf = &keygroup;
-       if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+       if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
                dprintk(1, "read error\n");
                return -EIO;
        }
@@ -286,7 +286,7 @@ static void ir_work(struct work_struct *work)
 
        /* MSI TV@nywhere Plus requires more frequent polling
           otherwise it will miss some keypresses */
-       if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30)
+       if (ir->c->adapter->id == I2C_HW_SAA7134 && ir->c->addr == 0x30)
                polling_interval = 50;
 
        ir_key_poll(ir);
@@ -295,34 +295,15 @@ static void ir_work(struct work_struct *work)
 
 /* ----------------------------------------------------------------------- */
 
-static int ir_attach(struct i2c_adapter *adap, int addr,
-                     unsigned short flags, int kind);
-static int ir_detach(struct i2c_client *client);
-static int ir_probe(struct i2c_adapter *adap);
-
-static struct i2c_driver driver = {
-       .driver = {
-               .name   = "ir-kbd-i2c",
-       },
-       .id             = I2C_DRIVERID_INFRARED,
-       .attach_adapter = ir_probe,
-       .detach_client  = ir_detach,
-};
-
-static struct i2c_client client_template =
-{
-       .name = "unset",
-       .driver = &driver
-};
-
-static int ir_attach(struct i2c_adapter *adap, int addr,
-                    unsigned short flags, int kind)
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        IR_KEYTAB_TYPE *ir_codes = NULL;
-       char *name;
+       const char *name = NULL;
        int ir_type;
        struct IR_i2c *ir;
        struct input_dev *input_dev;
+       struct i2c_adapter *adap = client->adapter;
+       unsigned short addr = client->addr;
        int err;
 
        ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
@@ -332,13 +313,9 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                goto err_out_free;
        }
 
-       ir->c = client_template;
+       ir->c = client;
        ir->input = input_dev;
-
-       ir->c.adapter = adap;
-       ir->c.addr    = addr;
-
-       i2c_set_clientdata(&ir->c, ir);
+       i2c_set_clientdata(client, ir);
 
        switch(addr) {
        case 0x64:
@@ -403,44 +380,46 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                ir_codes    = ir_codes_avermedia_cardbus;
                break;
        default:
-               /* shouldn't happen */
-               printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr);
+               dprintk(1, DEVNAME ": Unsupported i2c address 0x%02x\n", addr);
                err = -ENODEV;
                goto err_out_free;
        }
 
-       /* Sets name */
-       snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
-       ir->ir_codes = ir_codes;
+       /* Let the caller override settings */
+       if (client->dev.platform_data) {
+               const struct IR_i2c_init_data *init_data =
+                                               client->dev.platform_data;
 
-       /* register i2c device
-        * At device register, IR codes may be changed to be
-        * board dependent.
-        */
-       err = i2c_attach_client(&ir->c);
-       if (err)
-               goto err_out_free;
+               ir_codes = init_data->ir_codes;
+               name = init_data->name;
+               ir->get_key = init_data->get_key;
+       }
 
-       /* If IR not supported or disabled, unregisters driver */
-       if (ir->get_key == NULL) {
+       /* Make sure we are all setup before going on */
+       if (!name || !ir->get_key || !ir_codes) {
+               dprintk(1, DEVNAME ": Unsupported device at address 0x%02x\n",
+                       addr);
                err = -ENODEV;
-               goto err_out_detach;
+               goto err_out_free;
        }
 
-       /* Phys addr can only be set after attaching (for ir->c.dev) */
+       /* Sets name */
+       snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name);
+       ir->ir_codes = ir_codes;
+
        snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
-                dev_name(&ir->c.adapter->dev),
-                dev_name(&ir->c.dev));
+                dev_name(&adap->dev),
+                dev_name(&client->dev));
 
        /* init + register input device */
        ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
        input_dev->id.bustype = BUS_I2C;
-       input_dev->name       = ir->c.name;
+       input_dev->name       = ir->name;
        input_dev->phys       = ir->phys;
 
        err = input_register_device(ir->input);
        if (err)
-               goto err_out_detach;
+               goto err_out_free;
 
        printk(DEVNAME ": %s detected at %s [%s]\n",
               ir->input->name, ir->input->phys, adap->name);
@@ -451,135 +430,42 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
 
        return 0;
 
- err_out_detach:
-       i2c_detach_client(&ir->c);
  err_out_free:
        input_free_device(input_dev);
        kfree(ir);
        return err;
 }
 
-static int ir_detach(struct i2c_client *client)
+static int ir_remove(struct i2c_client *client)
 {
        struct IR_i2c *ir = i2c_get_clientdata(client);
 
        /* kill outstanding polls */
        cancel_delayed_work_sync(&ir->work);
 
-       /* unregister devices */
+       /* unregister device */
        input_unregister_device(ir->input);
-       i2c_detach_client(&ir->c);
 
        /* free memory */
        kfree(ir);
        return 0;
 }
 
-static int ir_probe(struct i2c_adapter *adap)
-{
-
-       /* The external IR receiver is at i2c address 0x34 (0x35 for
-          reads).  Future Hauppauge cards will have an internal
-          receiver at 0x30 (0x31 for reads).  In theory, both can be
-          fitted, and Hauppauge suggest an external overrides an
-          internal.
-
-          That's why we probe 0x1a (~0x34) first. CB
-       */
-
-       static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
-       static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 };
-       static const int probe_em28XX[] = { 0x30, 0x47, -1 };
-       static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
-       static const int probe_cx23885[] = { 0x6b, -1 };
-       const int *probe;
-       struct i2c_msg msg = {
-               .flags = I2C_M_RD,
-               .len = 0,
-               .buf = NULL,
-       };
-       int i, rc;
-
-       switch (adap->id) {
-       case I2C_HW_B_BT848:
-               probe = probe_bttv;
-               break;
-       case I2C_HW_B_CX2341X:
-               probe = probe_bttv;
-               break;
-       case I2C_HW_SAA7134:
-               probe = probe_saa7134;
-               break;
-       case I2C_HW_B_EM28XX:
-               probe = probe_em28XX;
-               break;
-       case I2C_HW_B_CX2388x:
-               probe = probe_cx88;
-               break;
-       case I2C_HW_B_CX23885:
-               probe = probe_cx23885;
-               break;
-       default:
-               return 0;
-       }
-
-       for (i = 0; -1 != probe[i]; i++) {
-               msg.addr = probe[i];
-               rc = i2c_transfer(adap, &msg, 1);
-               dprintk(1,"probe 0x%02x @ %s: %s\n",
-                       probe[i], adap->name,
-                       (1 == rc) ? "yes" : "no");
-               if (1 == rc) {
-                       ir_attach(adap, probe[i], 0, 0);
-                       return 0;
-               }
-       }
-
-       /* Special case for MSI TV@nywhere Plus remote */
-       if (adap->id == I2C_HW_SAA7134) {
-               u8 temp;
-
-               /* MSI TV@nywhere Plus controller doesn't seem to
-                  respond to probes unless we read something from
-                  an existing device. Weird... */
-
-               msg.addr = 0x50;
-               rc = i2c_transfer(adap, &msg, 1);
-                       dprintk(1, "probe 0x%02x @ %s: %s\n",
-                       msg.addr, adap->name,
-                       (1 == rc) ? "yes" : "no");
-
-               /* Now do the probe. The controller does not respond
-                  to 0-byte reads, so we use a 1-byte read instead. */
-               msg.addr = 0x30;
-               msg.len = 1;
-               msg.buf = &temp;
-               rc = i2c_transfer(adap, &msg, 1);
-               dprintk(1, "probe 0x%02x @ %s: %s\n",
-                       msg.addr, adap->name,
-                       (1 == rc) ? "yes" : "no");
-               if (1 == rc)
-                       ir_attach(adap, msg.addr, 0, 0);
-       }
-
-       /* Special case for AVerMedia Cardbus remote */
-       if (adap->id == I2C_HW_SAA7134) {
-               unsigned char subaddr, data;
-               struct i2c_msg msg[] = { { .addr = 0x40, .flags = 0,
-                                          .buf = &subaddr, .len = 1},
-                                        { .addr = 0x40, .flags = I2C_M_RD,
-                                          .buf = &data, .len = 1} };
-               subaddr = 0x0d;
-               rc = i2c_transfer(adap, msg, 2);
-               dprintk(1, "probe 0x%02x/0x%02x @ %s: %s\n",
-                       msg[0].addr, subaddr, adap->name,
-                       (2 == rc) ? "yes" : "no");
-               if (2 == rc)
-                       ir_attach(adap, msg[0].addr, 0, 0);
-       }
+static const struct i2c_device_id ir_kbd_id[] = {
+       /* Generic entry for any IR receiver */
+       { "ir_video", 0 },
+       /* IR device specific entries could be added here */
+       { }
+};
 
-       return 0;
-}
+static struct i2c_driver driver = {
+       .driver = {
+               .name   = "ir-kbd-i2c",
+       },
+       .probe          = ir_probe,
+       .remove         = ir_remove,
+       .id_table       = ir_kbd_id,
+};
 
 /* ----------------------------------------------------------------------- */
 
index db2ac9a99acd68b96f5af3e439acd4206ed3e01a..558f8a837ff4f14bd04721a5cdd554add2d03cbe 100644 (file)
@@ -455,7 +455,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
                        break;
        }
        if (tv.tuner_type == TUNER_ABSENT)
-               IVTV_ERR("tveeprom cannot autodetect tuner!");
+               IVTV_ERR("tveeprom cannot autodetect tuner!\n");
 
        if (itv->options.tuner == -1)
                itv->options.tuner = tv.tuner_type;
@@ -946,17 +946,14 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
        if (itv == NULL)
                return -ENOMEM;
        itv->pdev = pdev;
-       itv->instance = atomic_inc_return(&ivtv_instance) - 1;
+       itv->instance = v4l2_device_set_name(&itv->v4l2_dev, "ivtv",
+                                               &ivtv_instance);
 
        retval = v4l2_device_register(&pdev->dev, &itv->v4l2_dev);
        if (retval) {
                kfree(itv);
                return retval;
        }
-       /* "ivtv + PCI ID" is a bit of a mouthful, so use
-          "ivtv + instance" instead. */
-       snprintf(itv->v4l2_dev.name, sizeof(itv->v4l2_dev.name),
-                       "ivtv%d", itv->instance);
        IVTV_INFO("Initializing card %d\n", itv->instance);
 
        ivtv_process_options(itv);
index 9e3d32b8004c0e571b2b92e3db4363bab2f7b1fd..e52aa322b13426dc3139aff85f5af87927cd5f7d 100644 (file)
@@ -579,9 +579,11 @@ static struct i2c_client ivtv_i2c_client_template = {
        .name = "ivtv internal",
 };
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter + instantiate IR receiver */
 int init_ivtv_i2c(struct ivtv *itv)
 {
+       int retval;
+
        IVTV_DEBUG_I2C("i2c init\n");
 
        /* Sanity checks for the I2C hardware arrays. They must be the
@@ -619,9 +621,37 @@ int init_ivtv_i2c(struct ivtv *itv)
        ivtv_setsda(itv, 1);
 
        if (itv->options.newi2c > 0)
-               return i2c_add_adapter(&itv->i2c_adap);
+               retval = i2c_add_adapter(&itv->i2c_adap);
        else
-               return i2c_bit_add_bus(&itv->i2c_adap);
+               retval = i2c_bit_add_bus(&itv->i2c_adap);
+
+       /* Instantiate the IR receiver device, if present */
+       if (retval == 0) {
+               struct i2c_board_info info;
+               /* The external IR receiver is at i2c address 0x34 (0x35 for
+                  reads).  Future Hauppauge cards will have an internal
+                  receiver at 0x30 (0x31 for reads).  In theory, both can be
+                  fitted, and Hauppauge suggest an external overrides an
+                  internal.
+
+                  That's why we probe 0x1a (~0x34) first. CB
+               */
+               const unsigned short addr_list[] = {
+                       0x1a,   /* Hauppauge IR external */
+                       0x18,   /* Hauppauge IR internal */
+                       0x71,   /* Hauppauge IR (PVR150) */
+                       0x64,   /* Pixelview IR */
+                       0x30,   /* KNC ONE IR */
+                       0x6b,   /* Adaptec IR */
+                       I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&itv->i2c_adap, &info, addr_list);
+       }
+
+       return retval;
 }
 
 void exit_ivtv_i2c(struct ivtv *itv)
index c342a9fe983eab8246c912ac60070f25923a48bd..99f3c39a118b428ea04e4878f3c58a0ebc5da52d 100644 (file)
@@ -709,7 +709,7 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
        else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET &&
                        regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)
                reg_start = itv->dec_mem - IVTV_DECODER_OFFSET;
-       else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE)
+       else if (regs->reg < IVTV_ENCODER_SIZE)
                reg_start = itv->enc_mem;
        else
                return -EINVAL;
index 684f62fa7897586152db543a6a3c95069dea7cf0..459c04cbf69dd0fb9b23efeb869cda79d7135e15 100644 (file)
@@ -75,53 +75,50 @@ struct mt9m001 {
        unsigned char autoexposure;
 };
 
-static int reg_read(struct soc_camera_device *icd, const u8 reg)
+static int reg_read(struct i2c_client *client, const u8 reg)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       struct i2c_client *client = mt9m001->client;
        s32 data = i2c_smbus_read_word_data(client, reg);
        return data < 0 ? data : swab16(data);
 }
 
-static int reg_write(struct soc_camera_device *icd, const u8 reg,
+static int reg_write(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       return i2c_smbus_write_word_data(mt9m001->client, reg, swab16(data));
+       return i2c_smbus_write_word_data(client, reg, swab16(data));
 }
 
-static int reg_set(struct soc_camera_device *icd, const u8 reg,
+static int reg_set(struct i2c_client *client, const u8 reg,
                   const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret | data);
+       return reg_write(client, reg, ret | data);
 }
 
-static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+static int reg_clear(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret & ~data);
+       return reg_write(client, reg, ret & ~data);
 }
 
 static int mt9m001_init(struct soc_camera_device *icd)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        dev_dbg(icd->vdev->parent, "%s\n", __func__);
 
        if (icl->power) {
-               ret = icl->power(&mt9m001->client->dev, 1);
+               ret = icl->power(&client->dev, 1);
                if (ret < 0) {
                        dev_err(icd->vdev->parent,
                                "Platform failed to power-on the camera.\n");
@@ -131,49 +128,53 @@ static int mt9m001_init(struct soc_camera_device *icd)
 
        /* The camera could have been already on, we reset it additionally */
        if (icl->reset)
-               ret = icl->reset(&mt9m001->client->dev);
+               ret = icl->reset(&client->dev);
        else
                ret = -ENODEV;
 
        if (ret < 0) {
                /* Either no platform reset, or platform reset failed */
-               ret = reg_write(icd, MT9M001_RESET, 1);
+               ret = reg_write(client, MT9M001_RESET, 1);
                if (!ret)
-                       ret = reg_write(icd, MT9M001_RESET, 0);
+                       ret = reg_write(client, MT9M001_RESET, 0);
        }
        /* Disable chip, synchronous option update */
        if (!ret)
-               ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+               ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
 
        return ret;
 }
 
 static int mt9m001_release(struct soc_camera_device *icd)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
 
        /* Disable the chip */
-       reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+       reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
 
        if (icl->power)
-               icl->power(&mt9m001->client->dev, 0);
+               icl->power(&client->dev, 0);
 
        return 0;
 }
 
 static int mt9m001_start_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* Switch to master "normal" mode */
-       if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 2) < 0)
+       if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0)
                return -EIO;
        return 0;
 }
 
 static int mt9m001_stop_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* Stop sensor readout */
-       if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 0) < 0)
+       if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0)
                return -EIO;
        return 0;
 }
@@ -222,28 +223,29 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
 static int mt9m001_set_crop(struct soc_camera_device *icd,
                            struct v4l2_rect *rect)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
        int ret;
        const u16 hblank = 9, vblank = 25;
 
        /* Blanking and start values - default... */
-       ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
+       ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
        if (!ret)
-               ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
+               ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank);
 
        /* The caller provides a supported format, as verified per
         * call to icd->try_fmt() */
        if (!ret)
-               ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
+               ret = reg_write(client, MT9M001_COLUMN_START, rect->left);
        if (!ret)
-               ret = reg_write(icd, MT9M001_ROW_START, rect->top);
+               ret = reg_write(client, MT9M001_ROW_START, rect->top);
        if (!ret)
-               ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1);
+               ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect->width - 1);
        if (!ret)
-               ret = reg_write(icd, MT9M001_WINDOW_HEIGHT,
+               ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
                                rect->height + icd->y_skip_top - 1);
        if (!ret && mt9m001->autoexposure) {
-               ret = reg_write(icd, MT9M001_SHUTTER_WIDTH,
+               ret = reg_write(client, MT9M001_SHUTTER_WIDTH,
                                rect->height + icd->y_skip_top + vblank);
                if (!ret) {
                        const struct v4l2_queryctrl *qctrl =
@@ -312,16 +314,16 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd,
 static int mt9m001_get_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9m001->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
        reg->size = 2;
-       reg->val = reg_read(icd, reg->reg);
+       reg->val = reg_read(client, reg->reg);
 
        if (reg->val > 0xffff)
                return -EIO;
@@ -332,15 +334,15 @@ static int mt9m001_get_register(struct soc_camera_device *icd,
 static int mt9m001_set_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9m001->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       if (reg_write(icd, reg->reg, reg->val) < 0)
+       if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
        return 0;
@@ -416,12 +418,13 @@ static struct soc_camera_ops mt9m001_ops = {
 
 static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
        int data;
 
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
-               data = reg_read(icd, MT9M001_READ_OPTIONS2);
+               data = reg_read(client, MT9M001_READ_OPTIONS2);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x8000);
@@ -435,6 +438,7 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro
 
 static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
        const struct v4l2_queryctrl *qctrl;
        int data;
@@ -447,9 +451,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9M001_READ_OPTIONS2, 0x8000);
+                       data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000);
                else
-                       data = reg_clear(icd, MT9M001_READ_OPTIONS2, 0x8000);
+                       data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000);
                if (data < 0)
                        return -EIO;
                break;
@@ -463,7 +467,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
                        data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
 
                        dev_dbg(&icd->dev, "Setting gain %d\n", data);
-                       data = reg_write(icd, MT9M001_GLOBAL_GAIN, data);
+                       data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
                        if (data < 0)
                                return -EIO;
                } else {
@@ -481,8 +485,8 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
                                data = ((gain - 64) * 7 + 28) / 56 + 96;
 
                        dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
-                                reg_read(icd, MT9M001_GLOBAL_GAIN), data);
-                       data = reg_write(icd, MT9M001_GLOBAL_GAIN, data);
+                                reg_read(client, MT9M001_GLOBAL_GAIN), data);
+                       data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
                        if (data < 0)
                                return -EIO;
                }
@@ -500,8 +504,8 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
                                                 range / 2) / range + 1;
 
                        dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n",
-                                reg_read(icd, MT9M001_SHUTTER_WIDTH), shutter);
-                       if (reg_write(icd, MT9M001_SHUTTER_WIDTH, shutter) < 0)
+                                reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
+                       if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
                                return -EIO;
                        icd->exposure = ctrl->value;
                        mt9m001->autoexposure = 0;
@@ -510,7 +514,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
        case V4L2_CID_EXPOSURE_AUTO:
                if (ctrl->value) {
                        const u16 vblank = 25;
-                       if (reg_write(icd, MT9M001_SHUTTER_WIDTH, icd->height +
+                       if (reg_write(client, MT9M001_SHUTTER_WIDTH, icd->height +
                                      icd->y_skip_top + vblank) < 0)
                                return -EIO;
                        qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
@@ -529,8 +533,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
  * this wasn't our capture interface, so, we wait for the right one */
 static int mt9m001_video_probe(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        s32 data;
        int ret;
        unsigned long flags;
@@ -542,11 +547,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
                return -ENODEV;
 
        /* Enable the chip */
-       data = reg_write(icd, MT9M001_CHIP_ENABLE, 1);
+       data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
        dev_dbg(&icd->dev, "write: %d\n", data);
 
        /* Read out the chip version register */
-       data = reg_read(icd, MT9M001_CHIP_VERSION);
+       data = reg_read(client, MT9M001_CHIP_VERSION);
 
        /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
        switch (data) {
@@ -604,10 +609,13 @@ ei2c:
 static void mt9m001_video_remove(struct soc_camera_device *icd)
 {
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
 
        dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
                icd->dev.parent, icd->vdev);
        soc_camera_video_stop(icd);
+       if (icl->free_bus)
+               icl->free_bus(icl);
 }
 
 static int mt9m001_probe(struct i2c_client *client,
index cdd1ddb513881a3ec982454bc052c8a267346dc3..fc5e2de037663abcc3fd84e9c5d32bca71183ef9 100644 (file)
  * mt9m111: Camera control register addresses (0x200..0x2ff not implemented)
  */
 
-#define reg_read(reg) mt9m111_reg_read(icd, MT9M111_##reg)
-#define reg_write(reg, val) mt9m111_reg_write(icd, MT9M111_##reg, (val))
-#define reg_set(reg, val) mt9m111_reg_set(icd, MT9M111_##reg, (val))
-#define reg_clear(reg, val) mt9m111_reg_clear(icd, MT9M111_##reg, (val))
+#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg)
+#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
+#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
+#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
 
 #define MT9M111_MIN_DARK_ROWS  8
 #define MT9M111_MIN_DARK_COLS  24
@@ -184,58 +184,55 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg)
        return ret;
 }
 
-static int mt9m111_reg_read(struct soc_camera_device *icd, const u16 reg)
+static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
 {
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct i2c_client *client = mt9m111->client;
        int ret;
 
        ret = reg_page_map_set(client, reg);
        if (!ret)
                ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff)));
 
-       dev_dbg(&icd->dev, "read  reg.%03x -> %04x\n", reg, ret);
+       dev_dbg(&client->dev, "read  reg.%03x -> %04x\n", reg, ret);
        return ret;
 }
 
-static int mt9m111_reg_write(struct soc_camera_device *icd, const u16 reg,
+static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
                             const u16 data)
 {
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct i2c_client *client = mt9m111->client;
        int ret;
 
        ret = reg_page_map_set(client, reg);
        if (!ret)
-               ret = i2c_smbus_write_word_data(mt9m111->client, (reg & 0xff),
+               ret = i2c_smbus_write_word_data(client, (reg & 0xff),
                                                swab16(data));
-       dev_dbg(&icd->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
+       dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
        return ret;
 }
 
-static int mt9m111_reg_set(struct soc_camera_device *icd, const u16 reg,
+static int mt9m111_reg_set(struct i2c_client *client, const u16 reg,
                           const u16 data)
 {
        int ret;
 
-       ret = mt9m111_reg_read(icd, reg);
+       ret = mt9m111_reg_read(client, reg);
        if (ret >= 0)
-               ret = mt9m111_reg_write(icd, reg, ret | data);
+               ret = mt9m111_reg_write(client, reg, ret | data);
        return ret;
 }
 
-static int mt9m111_reg_clear(struct soc_camera_device *icd, const u16 reg,
+static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
                             const u16 data)
 {
        int ret;
 
-       ret = mt9m111_reg_read(icd, reg);
-       return mt9m111_reg_write(icd, reg, ret & ~data);
+       ret = mt9m111_reg_read(client, reg);
+       return mt9m111_reg_write(client, reg, ret & ~data);
 }
 
 static int mt9m111_set_context(struct soc_camera_device *icd,
                               enum mt9m111_context ctxt)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
                | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
                | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
@@ -252,6 +249,7 @@ static int mt9m111_set_context(struct soc_camera_device *icd,
 static int mt9m111_setup_rect(struct soc_camera_device *icd,
                              struct v4l2_rect *rect)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret, is_raw_format;
        int width = rect->width;
@@ -296,6 +294,7 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd,
 
 static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int ret;
 
        ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
@@ -357,12 +356,13 @@ static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
 
 static int mt9m111_enable(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        if (icl->power) {
-               ret = icl->power(&mt9m111->client->dev, 1);
+               ret = icl->power(&client->dev, 1);
                if (ret < 0) {
                        dev_err(icd->vdev->parent,
                                "Platform failed to power-on the camera.\n");
@@ -378,8 +378,9 @@ static int mt9m111_enable(struct soc_camera_device *icd)
 
 static int mt9m111_disable(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
@@ -387,15 +388,15 @@ static int mt9m111_disable(struct soc_camera_device *icd)
                mt9m111->powered = 0;
 
        if (icl->power)
-               icl->power(&mt9m111->client->dev, 0);
+               icl->power(&client->dev, 0);
 
        return ret;
 }
 
 static int mt9m111_reset(struct soc_camera_device *icd)
 {
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
@@ -406,7 +407,7 @@ static int mt9m111_reset(struct soc_camera_device *icd)
                                | MT9M111_RESET_RESET_SOC);
 
        if (icl->reset)
-               icl->reset(&mt9m111->client->dev);
+               icl->reset(&client->dev);
 
        return ret;
 }
@@ -562,15 +563,14 @@ static int mt9m111_get_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
        int val;
-
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
                return -EINVAL;
-       if (reg->match.addr != mt9m111->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       val = mt9m111_reg_read(icd, reg->reg);
+       val = mt9m111_reg_read(client, reg->reg);
        reg->size = 2;
        reg->val = (u64)val;
 
@@ -583,15 +583,15 @@ static int mt9m111_get_register(struct soc_camera_device *icd,
 static int mt9m111_set_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9m111->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0)
+       if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
        return 0;
@@ -672,6 +672,7 @@ static struct soc_camera_ops mt9m111_ops = {
 
 static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret;
 
@@ -692,6 +693,7 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
 
 static int mt9m111_get_global_gain(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int data;
 
        data = reg_read(GLOBAL_GAIN);
@@ -703,6 +705,7 @@ static int mt9m111_get_global_gain(struct soc_camera_device *icd)
 
 static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        u16 val;
 
        if (gain > 63 * 2 * 2)
@@ -721,6 +724,7 @@ static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
 
 static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret;
 
@@ -737,6 +741,7 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
 
 static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret;
 
@@ -754,6 +759,7 @@ static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
 static int mt9m111_get_control(struct soc_camera_device *icd,
                               struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int data;
 
@@ -898,6 +904,7 @@ static int mt9m111_release(struct soc_camera_device *icd)
  */
 static int mt9m111_video_probe(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        s32 data;
        int ret;
index 2b0927bfd217b1226366f370f6e09d4ee5c57dde..f72aeb7c4deb974afa6241566fd8b922858c9090 100644 (file)
@@ -76,64 +76,61 @@ struct mt9t031 {
        u16 yskip;
 };
 
-static int reg_read(struct soc_camera_device *icd, const u8 reg)
+static int reg_read(struct i2c_client *client, const u8 reg)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-       struct i2c_client *client = mt9t031->client;
        s32 data = i2c_smbus_read_word_data(client, reg);
        return data < 0 ? data : swab16(data);
 }
 
-static int reg_write(struct soc_camera_device *icd, const u8 reg,
+static int reg_write(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-       return i2c_smbus_write_word_data(mt9t031->client, reg, swab16(data));
+       return i2c_smbus_write_word_data(client, reg, swab16(data));
 }
 
-static int reg_set(struct soc_camera_device *icd, const u8 reg,
+static int reg_set(struct i2c_client *client, const u8 reg,
                   const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret | data);
+       return reg_write(client, reg, ret | data);
 }
 
-static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+static int reg_clear(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret & ~data);
+       return reg_write(client, reg, ret & ~data);
 }
 
-static int set_shutter(struct soc_camera_device *icd, const u32 data)
+static int set_shutter(struct i2c_client *client, const u32 data)
 {
        int ret;
 
-       ret = reg_write(icd, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
+       ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
 
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_SHUTTER_WIDTH, data & 0xffff);
+               ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff);
 
        return ret;
 }
 
-static int get_shutter(struct soc_camera_device *icd, u32 *data)
+static int get_shutter(struct i2c_client *client, u32 *data)
 {
        int ret;
 
-       ret = reg_read(icd, MT9T031_SHUTTER_WIDTH_UPPER);
+       ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER);
        *data = ret << 16;
 
        if (ret >= 0)
-               ret = reg_read(icd, MT9T031_SHUTTER_WIDTH);
+               ret = reg_read(client, MT9T031_SHUTTER_WIDTH);
        *data |= ret & 0xffff;
 
        return ret < 0 ? ret : 0;
@@ -141,12 +138,12 @@ static int get_shutter(struct soc_camera_device *icd, u32 *data)
 
 static int mt9t031_init(struct soc_camera_device *icd)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-       struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        if (icl->power) {
-               ret = icl->power(&mt9t031->client->dev, 1);
+               ret = icl->power(&client->dev, 1);
                if (ret < 0) {
                        dev_err(icd->vdev->parent,
                                "Platform failed to power-on the camera.\n");
@@ -155,44 +152,48 @@ static int mt9t031_init(struct soc_camera_device *icd)
        }
 
        /* Disable chip output, synchronous option update */
-       ret = reg_write(icd, MT9T031_RESET, 1);
+       ret = reg_write(client, MT9T031_RESET, 1);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_RESET, 0);
+               ret = reg_write(client, MT9T031_RESET, 0);
        if (ret >= 0)
-               ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
+               ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
 
        if (ret < 0 && icl->power)
-               icl->power(&mt9t031->client->dev, 0);
+               icl->power(&client->dev, 0);
 
        return ret >= 0 ? 0 : -EIO;
 }
 
 static int mt9t031_release(struct soc_camera_device *icd)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-       struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
 
        /* Disable the chip */
-       reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
+       reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
 
        if (icl->power)
-               icl->power(&mt9t031->client->dev, 0);
+               icl->power(&client->dev, 0);
 
        return 0;
 }
 
 static int mt9t031_start_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* Switch to master "normal" mode */
-       if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
+       if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
                return -EIO;
        return 0;
 }
 
 static int mt9t031_stop_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* Stop sensor readout */
-       if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
+       if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
                return -EIO;
        return 0;
 }
@@ -200,14 +201,16 @@ static int mt9t031_stop_capture(struct soc_camera_device *icd)
 static int mt9t031_set_bus_param(struct soc_camera_device *icd,
                                 unsigned long flags)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* The caller should have queried our parameters, check anyway */
        if (flags & ~MT9T031_BUS_PARAM)
                return -EINVAL;
 
        if (flags & SOCAM_PCLK_SAMPLE_FALLING)
-               reg_clear(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+               reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
        else
-               reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+               reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
 
        return 0;
 }
@@ -235,6 +238,7 @@ static void recalculate_limits(struct soc_camera_device *icd,
 static int mt9t031_set_params(struct soc_camera_device *icd,
                              struct v4l2_rect *rect, u16 xskip, u16 yskip)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
        int ret;
        u16 xbin, ybin, width, height, left, top;
@@ -277,22 +281,22 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
        }
 
        /* Disable register update, reconfigure atomically */
-       ret = reg_set(icd, MT9T031_OUTPUT_CONTROL, 1);
+       ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1);
        if (ret < 0)
                return ret;
 
        /* Blanking and start values - default... */
-       ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank);
+       ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank);
+               ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank);
 
        if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) {
                /* Binning, skipping */
                if (ret >= 0)
-                       ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE,
+                       ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
                                        ((xbin - 1) << 4) | (xskip - 1));
                if (ret >= 0)
-                       ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE,
+                       ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
                                        ((ybin - 1) << 4) | (yskip - 1));
        }
        dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top);
@@ -300,16 +304,16 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
        /* The caller provides a supported format, as guaranteed by
         * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_COLUMN_START, left);
+               ret = reg_write(client, MT9T031_COLUMN_START, left);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_ROW_START, top);
+               ret = reg_write(client, MT9T031_ROW_START, top);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1);
+               ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_WINDOW_HEIGHT,
+               ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
                                height + icd->y_skip_top - 1);
        if (ret >= 0 && mt9t031->autoexposure) {
-               ret = set_shutter(icd, height + icd->y_skip_top + vblank);
+               ret = set_shutter(client, height + icd->y_skip_top + vblank);
                if (ret >= 0) {
                        const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
                        const struct v4l2_queryctrl *qctrl =
@@ -324,7 +328,7 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
 
        /* Re-enable register update, commit all changes */
        if (ret >= 0)
-               ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1);
+               ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1);
 
        return ret < 0 ? ret : 0;
 }
@@ -417,15 +421,15 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd,
 static int mt9t031_get_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9t031->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       reg->val = reg_read(icd, reg->reg);
+       reg->val = reg_read(client, reg->reg);
 
        if (reg->val > 0xffff)
                return -EIO;
@@ -436,15 +440,15 @@ static int mt9t031_get_register(struct soc_camera_device *icd,
 static int mt9t031_set_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9t031->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       if (reg_write(icd, reg->reg, reg->val) < 0)
+       if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
        return 0;
@@ -528,18 +532,19 @@ static struct soc_camera_ops mt9t031_ops = {
 
 static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
        int data;
 
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
-               data = reg_read(icd, MT9T031_READ_MODE_2);
+               data = reg_read(client, MT9T031_READ_MODE_2);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x8000);
                break;
        case V4L2_CID_HFLIP:
-               data = reg_read(icd, MT9T031_READ_MODE_2);
+               data = reg_read(client, MT9T031_READ_MODE_2);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x4000);
@@ -553,6 +558,7 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro
 
 static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
        const struct v4l2_queryctrl *qctrl;
        int data;
@@ -565,17 +571,17 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9T031_READ_MODE_2, 0x8000);
+                       data = reg_set(client, MT9T031_READ_MODE_2, 0x8000);
                else
-                       data = reg_clear(icd, MT9T031_READ_MODE_2, 0x8000);
+                       data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000);
                if (data < 0)
                        return -EIO;
                break;
        case V4L2_CID_HFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9T031_READ_MODE_2, 0x4000);
+                       data = reg_set(client, MT9T031_READ_MODE_2, 0x4000);
                else
-                       data = reg_clear(icd, MT9T031_READ_MODE_2, 0x4000);
+                       data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000);
                if (data < 0)
                        return -EIO;
                break;
@@ -589,7 +595,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
                        data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
 
                        dev_dbg(&icd->dev, "Setting gain %d\n", data);
-                       data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
+                       data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
                        if (data < 0)
                                return -EIO;
                } else {
@@ -609,8 +615,8 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
                                data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
 
                        dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n",
-                               reg_read(icd, MT9T031_GLOBAL_GAIN), data);
-                       data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
+                               reg_read(client, MT9T031_GLOBAL_GAIN), data);
+                       data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
                        if (data < 0)
                                return -EIO;
                }
@@ -628,10 +634,10 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
                                             range / 2) / range + 1;
                        u32 old;
 
-                       get_shutter(icd, &old);
+                       get_shutter(client, &old);
                        dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n",
                                old, shutter);
-                       if (set_shutter(icd, shutter) < 0)
+                       if (set_shutter(client, shutter) < 0)
                                return -EIO;
                        icd->exposure = ctrl->value;
                        mt9t031->autoexposure = 0;
@@ -641,7 +647,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
                if (ctrl->value) {
                        const u16 vblank = MT9T031_VERTICAL_BLANK;
                        const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
-                       if (set_shutter(icd, icd->height +
+                       if (set_shutter(client, icd->height +
                                        icd->y_skip_top + vblank) < 0)
                                return -EIO;
                        qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
@@ -661,6 +667,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
  * this wasn't our capture interface, so, we wait for the right one */
 static int mt9t031_video_probe(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
        s32 data;
        int ret;
@@ -672,11 +679,11 @@ static int mt9t031_video_probe(struct soc_camera_device *icd)
                return -ENODEV;
 
        /* Enable the chip */
-       data = reg_write(icd, MT9T031_CHIP_ENABLE, 1);
+       data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
        dev_dbg(&icd->dev, "write: %d\n", data);
 
        /* Read out the chip version register */
-       data = reg_read(icd, MT9T031_CHIP_VERSION);
+       data = reg_read(client, MT9T031_CHIP_VERSION);
 
        switch (data) {
        case 0x1621:
index 4d3b4813c322e67dc46c2c8c272a8db1ba1c728f..be20d312b1dc5784f8c85a63a367c2e219d467c0 100644 (file)
@@ -91,51 +91,49 @@ struct mt9v022 {
        u16 chip_control;
 };
 
-static int reg_read(struct soc_camera_device *icd, const u8 reg)
+static int reg_read(struct i2c_client *client, const u8 reg)
 {
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       struct i2c_client *client = mt9v022->client;
        s32 data = i2c_smbus_read_word_data(client, reg);
        return data < 0 ? data : swab16(data);
 }
 
-static int reg_write(struct soc_camera_device *icd, const u8 reg,
+static int reg_write(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       return i2c_smbus_write_word_data(mt9v022->client, reg, swab16(data));
+       return i2c_smbus_write_word_data(client, reg, swab16(data));
 }
 
-static int reg_set(struct soc_camera_device *icd, const u8 reg,
+static int reg_set(struct i2c_client *client, const u8 reg,
                   const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret | data);
+       return reg_write(client, reg, ret | data);
 }
 
-static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+static int reg_clear(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret & ~data);
+       return reg_write(client, reg, ret & ~data);
 }
 
 static int mt9v022_init(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        if (icl->power) {
-               ret = icl->power(&mt9v022->client->dev, 1);
+               ret = icl->power(&client->dev, 1);
                if (ret < 0) {
                        dev_err(icd->vdev->parent,
                                "Platform failed to power-on the camera.\n");
@@ -148,27 +146,27 @@ static int mt9v022_init(struct soc_camera_device *icd)
         * if available. Soft reset is done in video_probe().
         */
        if (icl->reset)
-               icl->reset(&mt9v022->client->dev);
+               icl->reset(&client->dev);
 
        /* Almost the default mode: master, parallel, simultaneous, and an
         * undocumented bit 0x200, which is present in table 7, but not in 8,
         * plus snapshot mode to disable scan for now */
        mt9v022->chip_control |= 0x10;
-       ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
        if (!ret)
-               ret = reg_write(icd, MT9V022_READ_MODE, 0x300);
+               ret = reg_write(client, MT9V022_READ_MODE, 0x300);
 
        /* All defaults */
        if (!ret)
                /* AEC, AGC on */
-               ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3);
+               ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
        if (!ret)
-               ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
+               ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
        if (!ret)
                /* default - auto */
-               ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
+               ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
        if (!ret)
-               ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0);
+               ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
 
        return ret;
 }
@@ -186,10 +184,11 @@ static int mt9v022_release(struct soc_camera_device *icd)
 
 static int mt9v022_start_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
        /* Switch to master "normal" mode */
        mt9v022->chip_control &= ~0x10;
-       if (reg_write(icd, MT9V022_CHIP_CONTROL,
+       if (reg_write(client, MT9V022_CHIP_CONTROL,
                      mt9v022->chip_control) < 0)
                return -EIO;
        return 0;
@@ -197,10 +196,11 @@ static int mt9v022_start_capture(struct soc_camera_device *icd)
 
 static int mt9v022_stop_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
        /* Switch to snapshot mode */
        mt9v022->chip_control |= 0x10;
-       if (reg_write(icd, MT9V022_CHIP_CONTROL,
+       if (reg_write(client, MT9V022_CHIP_CONTROL,
                      mt9v022->chip_control) < 0)
                return -EIO;
        return 0;
@@ -209,8 +209,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd)
 static int mt9v022_set_bus_param(struct soc_camera_device *icd,
                                 unsigned long flags)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
        int ret;
        u16 pixclk = 0;
@@ -243,14 +244,14 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
        if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
                pixclk |= 0x2;
 
-       ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
+       ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk);
        if (ret < 0)
                return ret;
 
        if (!(flags & SOCAM_MASTER))
                mt9v022->chip_control &= ~0x8;
 
-       ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
        if (ret < 0)
                return ret;
 
@@ -282,35 +283,36 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
 static int mt9v022_set_crop(struct soc_camera_device *icd,
                            struct v4l2_rect *rect)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int ret;
 
        /* Like in example app. Contradicts the datasheet though */
-       ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+       ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
        if (ret >= 0) {
                if (ret & 1) /* Autoexposure */
-                       ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
+                       ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
                                        rect->height + icd->y_skip_top + 43);
                else
-                       ret = reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH,
+                       ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
                                        rect->height + icd->y_skip_top + 43);
        }
        /* Setup frame format: defaults apart from width and height */
        if (!ret)
-               ret = reg_write(icd, MT9V022_COLUMN_START, rect->left);
+               ret = reg_write(client, MT9V022_COLUMN_START, rect->left);
        if (!ret)
-               ret = reg_write(icd, MT9V022_ROW_START, rect->top);
+               ret = reg_write(client, MT9V022_ROW_START, rect->top);
        if (!ret)
                /* Default 94, Phytec driver says:
                 * "width + horizontal blank >= 660" */
-               ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING,
+               ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
                                rect->width > 660 - 43 ? 43 :
                                660 - rect->width);
        if (!ret)
-               ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45);
+               ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
        if (!ret)
-               ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width);
+               ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width);
        if (!ret)
-               ret = reg_write(icd, MT9V022_WINDOW_HEIGHT,
+               ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
                                rect->height + icd->y_skip_top);
 
        if (ret < 0)
@@ -396,16 +398,16 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd,
 static int mt9v022_get_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9v022->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
        reg->size = 2;
-       reg->val = reg_read(icd, reg->reg);
+       reg->val = reg_read(client, reg->reg);
 
        if (reg->val > 0xffff)
                return -EIO;
@@ -416,15 +418,15 @@ static int mt9v022_get_register(struct soc_camera_device *icd,
 static int mt9v022_set_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9v022->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       if (reg_write(icd, reg->reg, reg->val) < 0)
+       if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
        return 0;
@@ -517,29 +519,30 @@ static struct soc_camera_ops mt9v022_ops = {
 static int mt9v022_get_control(struct soc_camera_device *icd,
                               struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int data;
 
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
-               data = reg_read(icd, MT9V022_READ_MODE);
+               data = reg_read(client, MT9V022_READ_MODE);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x10);
                break;
        case V4L2_CID_HFLIP:
-               data = reg_read(icd, MT9V022_READ_MODE);
+               data = reg_read(client, MT9V022_READ_MODE);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x20);
                break;
        case V4L2_CID_EXPOSURE_AUTO:
-               data = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+               data = reg_read(client, MT9V022_AEC_AGC_ENABLE);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x1);
                break;
        case V4L2_CID_AUTOGAIN:
-               data = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+               data = reg_read(client, MT9V022_AEC_AGC_ENABLE);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x2);
@@ -552,6 +555,7 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
                               struct v4l2_control *ctrl)
 {
        int data;
+       struct i2c_client *client = to_i2c_client(icd->control);
        const struct v4l2_queryctrl *qctrl;
 
        qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
@@ -562,17 +566,17 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9V022_READ_MODE, 0x10);
+                       data = reg_set(client, MT9V022_READ_MODE, 0x10);
                else
-                       data = reg_clear(icd, MT9V022_READ_MODE, 0x10);
+                       data = reg_clear(client, MT9V022_READ_MODE, 0x10);
                if (data < 0)
                        return -EIO;
                break;
        case V4L2_CID_HFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9V022_READ_MODE, 0x20);
+                       data = reg_set(client, MT9V022_READ_MODE, 0x20);
                else
-                       data = reg_clear(icd, MT9V022_READ_MODE, 0x20);
+                       data = reg_clear(client, MT9V022_READ_MODE, 0x20);
                if (data < 0)
                        return -EIO;
                break;
@@ -593,12 +597,12 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
                        /* The user wants to set gain manually, hope, she
                         * knows, what she's doing... Switch AGC off. */
 
-                       if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+                       if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
                                return -EIO;
 
                        dev_info(&icd->dev, "Setting gain from %d to %lu\n",
-                                reg_read(icd, MT9V022_ANALOG_GAIN), gain);
-                       if (reg_write(icd, MT9V022_ANALOG_GAIN, gain) < 0)
+                                reg_read(client, MT9V022_ANALOG_GAIN), gain);
+                       if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0)
                                return -EIO;
                        icd->gain = ctrl->value;
                }
@@ -614,13 +618,13 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
                        /* The user wants to set shutter width manually, hope,
                         * she knows, what she's doing... Switch AEC off. */
 
-                       if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1) < 0)
+                       if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0)
                                return -EIO;
 
                        dev_dbg(&icd->dev, "Shutter width from %d to %lu\n",
-                               reg_read(icd, MT9V022_TOTAL_SHUTTER_WIDTH),
+                               reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
                                shutter);
-                       if (reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH,
+                       if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
                                      shutter) < 0)
                                return -EIO;
                        icd->exposure = ctrl->value;
@@ -628,17 +632,17 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
                break;
        case V4L2_CID_AUTOGAIN:
                if (ctrl->value)
-                       data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x2);
+                       data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2);
                else
-                       data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2);
+                       data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2);
                if (data < 0)
                        return -EIO;
                break;
        case V4L2_CID_EXPOSURE_AUTO:
                if (ctrl->value)
-                       data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x1);
+                       data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
                else
-                       data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1);
+                       data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
                if (data < 0)
                        return -EIO;
                break;
@@ -650,8 +654,9 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
  * this wasn't our capture interface, so, we wait for the right one */
 static int mt9v022_video_probe(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        s32 data;
        int ret;
        unsigned long flags;
@@ -661,7 +666,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
                return -ENODEV;
 
        /* Read out the chip version register */
-       data = reg_read(icd, MT9V022_CHIP_VERSION);
+       data = reg_read(client, MT9V022_CHIP_VERSION);
 
        /* must be 0x1311 or 0x1313 */
        if (data != 0x1311 && data != 0x1313) {
@@ -672,12 +677,12 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
        }
 
        /* Soft reset */
-       ret = reg_write(icd, MT9V022_RESET, 1);
+       ret = reg_write(client, MT9V022_RESET, 1);
        if (ret < 0)
                goto ei2c;
        /* 15 clock cycles */
        udelay(200);
-       if (reg_read(icd, MT9V022_RESET)) {
+       if (reg_read(client, MT9V022_RESET)) {
                dev_err(&icd->dev, "Resetting MT9V022 failed!\n");
                goto ei2c;
        }
@@ -685,11 +690,11 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
        /* Set monochrome or colour sensor type */
        if (sensor_type && (!strcmp("colour", sensor_type) ||
                            !strcmp("color", sensor_type))) {
-               ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
+               ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
                icd->formats = mt9v022_colour_formats;
        } else {
-               ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
+               ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
                icd->formats = mt9v022_monochrome_formats;
        }
@@ -735,10 +740,13 @@ ei2c:
 static void mt9v022_video_remove(struct soc_camera_device *icd)
 {
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
 
        dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
                icd->dev.parent, icd->vdev);
        soc_camera_video_stop(icd);
+       if (icl->free_bus)
+               icl->free_bus(icl);
 }
 
 static int mt9v022_probe(struct i2c_client *client,
index 86fab56c5a203abb884f0940bcd07a039f6f2180..2d075205bdfe4b724e22882aa5e6a636edf81cef 100644 (file)
@@ -102,10 +102,10 @@ struct mx1_buffer {
  * Interface. If anyone ever builds hardware to enable more than
  * one camera, they will have to modify this driver too */
 struct mx1_camera_dev {
+       struct soc_camera_host          soc_host;
        struct soc_camera_device        *icd;
        struct mx1_camera_pdata         *pdata;
        struct mx1_buffer               *active;
-       struct device                   *dev;
        struct resource                 *res;
        struct clk                      *clk;
        struct list_head                capture;
@@ -219,7 +219,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
        int ret;
 
        if (unlikely(!pcdev->active)) {
-               dev_err(pcdev->dev, "DMA End IRQ with no active buffer\n");
+               dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n");
                return -EFAULT;
        }
 
@@ -229,7 +229,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
                vbuf->size, pcdev->res->start +
                CSIRXR, DMA_MODE_READ);
        if (unlikely(ret))
-               dev_err(pcdev->dev, "Failed to setup DMA sg list\n");
+               dev_err(pcdev->soc_host.dev, "Failed to setup DMA sg list\n");
 
        return ret;
 }
@@ -338,14 +338,14 @@ static void mx1_camera_dma_irq(int channel, void *data)
        imx_dma_disable(channel);
 
        if (unlikely(!pcdev->active)) {
-               dev_err(pcdev->dev, "DMA End IRQ with no active buffer\n");
+               dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n");
                goto out;
        }
 
        vb = &pcdev->active->vb;
        buf = container_of(vb, struct mx1_buffer, vb);
        WARN_ON(buf->inwork || list_empty(&vb->queue));
-       dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(pcdev->soc_host.dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        mx1_camera_wakeup(pcdev, vb, buf);
@@ -366,7 +366,7 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q,
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct mx1_camera_dev *pcdev = ici->priv;
 
-       videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, pcdev->dev,
+       videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, ici->dev,
                                        &pcdev->lock,
                                        V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                        V4L2_FIELD_NONE,
@@ -385,7 +385,7 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
         * they get a nice Oops */
        div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
 
-       dev_dbg(pcdev->dev, "System clock %lukHz, target freq %dkHz, "
+       dev_dbg(pcdev->soc_host.dev, "System clock %lukHz, target freq %dkHz, "
                "divisor %lu\n", lcdclk / 1000, mclk / 1000, div);
 
        return div;
@@ -395,7 +395,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 {
        unsigned int csicr1 = CSICR1_EN;
 
-       dev_dbg(pcdev->dev, "Activate device\n");
+       dev_dbg(pcdev->soc_host.dev, "Activate device\n");
 
        clk_enable(pcdev->clk);
 
@@ -411,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 
 static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
 {
-       dev_dbg(pcdev->dev, "Deactivate device\n");
+       dev_dbg(pcdev->soc_host.dev, "Deactivate device\n");
 
        /* Disable all CSI interface */
        __raw_writel(0x00, pcdev->base + CSICR1);
@@ -550,7 +550,7 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+               dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
                return -EINVAL;
        }
 
@@ -633,12 +633,6 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = {
        .querycap       = mx1_camera_querycap,
 };
 
-/* Should be allocated dynamically too, but we have only one. */
-static struct soc_camera_host mx1_soc_camera_host = {
-       .drv_name       = DRIVER_NAME,
-       .ops            = &mx1_soc_camera_host_ops,
-};
-
 static struct fiq_handler fh = {
        .name           = "csi_sof"
 };
@@ -673,7 +667,6 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
                goto exit_put_clk;
        }
 
-       dev_set_drvdata(&pdev->dev, pcdev);
        pcdev->res = res;
        pcdev->clk = clk;
 
@@ -707,16 +700,15 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
        }
        pcdev->irq = irq;
        pcdev->base = base;
-       pcdev->dev = &pdev->dev;
 
        /* request dma */
        pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH);
        if (pcdev->dma_chan < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for MX1 CSI\n");
+               dev_err(&pdev->dev, "Can't request DMA for MX1 CSI\n");
                err = -EBUSY;
                goto exit_iounmap;
        }
-       dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chan);
+       dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chan);
 
        imx_dma_setup_handlers(pcdev->dma_chan, mx1_camera_dma_irq, NULL,
                               pcdev);
@@ -729,7 +721,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
        /* request irq */
        err = claim_fiq(&fh);
        if (err) {
-               dev_err(pcdev->dev, "Camera interrupt register failed \n");
+               dev_err(&pdev->dev, "Camera interrupt register failed \n");
                goto exit_free_dma;
        }
 
@@ -746,10 +738,12 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
        mxc_set_irq_fiq(irq, 1);
        enable_fiq(irq);
 
-       mx1_soc_camera_host.priv        = pcdev;
-       mx1_soc_camera_host.dev.parent  = &pdev->dev;
-       mx1_soc_camera_host.nr          = pdev->id;
-       err = soc_camera_host_register(&mx1_soc_camera_host);
+       pcdev->soc_host.drv_name        = DRIVER_NAME;
+       pcdev->soc_host.ops             = &mx1_soc_camera_host_ops;
+       pcdev->soc_host.priv            = pcdev;
+       pcdev->soc_host.dev             = &pdev->dev;
+       pcdev->soc_host.nr              = pdev->id;
+       err = soc_camera_host_register(&pcdev->soc_host);
        if (err)
                goto exit_free_irq;
 
@@ -777,7 +771,9 @@ exit:
 
 static int __exit mx1_camera_remove(struct platform_device *pdev)
 {
-       struct mx1_camera_dev *pcdev = platform_get_drvdata(pdev);
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct mx1_camera_dev *pcdev = container_of(soc_host,
+                                       struct mx1_camera_dev, soc_host);
        struct resource *res;
 
        imx_dma_free(pcdev->dma_chan);
@@ -787,7 +783,7 @@ static int __exit mx1_camera_remove(struct platform_device *pdev)
 
        clk_put(pcdev->clk);
 
-       soc_camera_host_unregister(&mx1_soc_camera_host);
+       soc_camera_host_unregister(soc_host);
 
        iounmap(pcdev->base);
 
index 2d0781118eb06f3498238accddb4b5c1f6049af2..e605c076ed89d43ae5533e98d5d4dc60009dfd19 100644 (file)
@@ -87,7 +87,6 @@ struct mx3_camera_buffer {
  * @soc_host:          embedded soc_host object
  */
 struct mx3_camera_dev {
-       struct device           *dev;
        /*
         * i.MX3x is only supposed to handle one camera on its Camera Sensor
         * Interface. If anyone ever builds hardware to enable more than one
@@ -431,7 +430,7 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q,
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
 
-       videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, mx3_cam->dev,
+       videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, ici->dev,
                                       &mx3_cam->lock,
                                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                       V4L2_FIELD_NONE,
@@ -599,7 +598,8 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
                *flags |= SOCAM_DATAWIDTH_4;
                break;
        default:
-               dev_info(mx3_cam->dev, "Unsupported bus width %d\n", buswidth);
+               dev_info(mx3_cam->soc_host.dev, "Unsupported bus width %d\n",
+                        buswidth);
                return -EINVAL;
        }
 
@@ -614,7 +614,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
        unsigned long bus_flags, camera_flags;
        int ret = test_platform_param(mx3_cam, depth, &bus_flags);
 
-       dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", depth, ret);
+       dev_dbg(ici->dev, "requested bus width %d bit: %d\n", depth, ret);
 
        if (ret < 0)
                return ret;
@@ -637,7 +637,7 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
        if (!rq)
                return false;
 
-       pdata = rq->mx3_cam->dev->platform_data;
+       pdata = rq->mx3_cam->soc_host.dev->platform_data;
 
        return rq->id == chan->chan_id &&
                pdata->dma_dev == chan->device->dev;
@@ -697,7 +697,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(ici->dev, "Providing format %s using %s\n",
                                mx3_camera_formats[0].name,
                                icd->formats[idx].name);
                }
@@ -709,7 +709,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(ici->dev, "Providing format %s using %s\n",
                                mx3_camera_formats[0].name,
                                icd->formats[idx].name);
                }
@@ -722,7 +722,7 @@ passthrough:
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev,
+                       dev_dbg(ici->dev,
                                "Providing format %s in pass-through mode\n",
                                icd->formats[idx].name);
                }
@@ -829,7 +829,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+               dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
                return -EINVAL;
        }
 
@@ -866,7 +866,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (pixfmt && !xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -933,11 +933,11 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
-       dev_dbg(&ici->dev, "requested bus width %d bit: %d\n",
+       dev_dbg(ici->dev, "requested bus width %d bit: %d\n",
                icd->buswidth, ret);
 
        if (ret < 0)
@@ -947,7 +947,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 
        common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
        if (!common_flags) {
-               dev_dbg(&ici->dev, "no common flags: camera %lx, host %lx\n",
+               dev_dbg(ici->dev, "no common flags: camera %lx, host %lx\n",
                        camera_flags, bus_flags);
                return -EINVAL;
        }
@@ -1054,7 +1054,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 
        csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
 
-       dev_dbg(&ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw);
+       dev_dbg(ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw);
 
        return 0;
 }
@@ -1074,7 +1074,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
        .set_bus_param  = mx3_camera_set_bus_param,
 };
 
-static int mx3_camera_probe(struct platform_device *pdev)
+static int __devinit mx3_camera_probe(struct platform_device *pdev)
 {
        struct mx3_camera_dev *mx3_cam;
        struct resource *res;
@@ -1102,8 +1102,6 @@ static int mx3_camera_probe(struct platform_device *pdev)
                goto eclkget;
        }
 
-       dev_set_drvdata(&pdev->dev, mx3_cam);
-
        mx3_cam->pdata = pdev->dev.platform_data;
        mx3_cam->platform_flags = mx3_cam->pdata->flags;
        if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 |
@@ -1135,14 +1133,14 @@ static int mx3_camera_probe(struct platform_device *pdev)
        }
 
        mx3_cam->base   = base;
-       mx3_cam->dev    = &pdev->dev;
 
        soc_host                = &mx3_cam->soc_host;
        soc_host->drv_name      = MX3_CAM_DRV_NAME;
        soc_host->ops           = &mx3_soc_camera_host_ops;
        soc_host->priv          = mx3_cam;
-       soc_host->dev.parent    = &pdev->dev;
+       soc_host->dev           = &pdev->dev;
        soc_host->nr            = pdev->id;
+
        err = soc_camera_host_register(soc_host);
        if (err)
                goto ecamhostreg;
@@ -1165,11 +1163,13 @@ egetres:
 
 static int __devexit mx3_camera_remove(struct platform_device *pdev)
 {
-       struct mx3_camera_dev *mx3_cam = platform_get_drvdata(pdev);
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct mx3_camera_dev *mx3_cam = container_of(soc_host,
+                                       struct mx3_camera_dev, soc_host);
 
        clk_put(mx3_cam->clk);
 
-       soc_camera_host_unregister(&mx3_cam->soc_host);
+       soc_camera_host_unregister(soc_host);
 
        iounmap(mx3_cam->base);
 
@@ -1194,11 +1194,11 @@ static struct platform_driver mx3_camera_driver = {
                .name   = MX3_CAM_DRV_NAME,
        },
        .probe          = mx3_camera_probe,
-       .remove         = __exit_p(mx3_camera_remove),
+       .remove         = __devexit_p(mx3_camera_remove),
 };
 
 
-static int __devinit mx3_camera_init(void)
+static int __init mx3_camera_init(void)
 {
        return platform_driver_register(&mx3_camera_driver);
 }
index 3be5a71bdac284b5ccc866bd1d6eff39f4dc0246..35890e8b2431740a63a16cb3dd8ac377a50640c2 100644 (file)
@@ -453,7 +453,7 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
        DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
-       if (i->index < 0 || i->index >= MXB_INPUTS)
+       if (i->index >= MXB_INPUTS)
                return -EINVAL;
        memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
        return 0;
@@ -616,7 +616,7 @@ static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-       if (a->index < 0 || a->index > MXB_INPUTS) {
+       if (a->index > MXB_INPUTS) {
                DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
                return -EINVAL;
        }
index 9af5532db1423eb1d7971e5a00396a49c03f1959..08cfd3e4ae8abe8c6b96059b35c76fb42f1db94b 100644 (file)
@@ -112,6 +112,8 @@ static int framedrop                = -1;
 static int fastset;
 static int force_palette;
 static int backlight;
+/* Bitmask marking allocated devices from 0 to OV511_MAX_UNIT_VIDEO */
+static unsigned long ov511_devused;
 static int unit_video[OV511_MAX_UNIT_VIDEO];
 static int remove_zeros;
 static int mirror;
@@ -5720,7 +5722,7 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct usb_device *dev = interface_to_usbdev(intf);
        struct usb_interface_descriptor *idesc;
        struct usb_ov511 *ov;
-       int i;
+       int i, rc, nr;
 
        PDEBUG(1, "probing for device...");
 
@@ -5845,33 +5847,41 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
        ov->vdev->parent = &intf->dev;
        video_set_drvdata(ov->vdev, ov);
 
-       for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
-               /* Minor 0 cannot be specified; assume user wants autodetect */
-               if (unit_video[i] == 0)
-                       break;
+       mutex_lock(&ov->lock);
 
-               if (video_register_device(ov->vdev, VFL_TYPE_GRABBER,
-                       unit_video[i]) >= 0) {
-                       break;
-               }
-       }
+       /* Check to see next free device and mark as used */
+       nr = find_first_zero_bit(&ov511_devused, OV511_MAX_UNIT_VIDEO);
+
+       /* Registers device */
+       if (unit_video[nr] != 0)
+               rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER,
+                                          unit_video[nr]);
+       else
+               rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1);
 
-       /* Use the next available one */
-       if ((ov->vdev->minor == -1) &&
-           video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) {
+       if (rc < 0) {
                err("video_register_device failed");
+               mutex_unlock(&ov->lock);
                goto error;
        }
 
+       /* Mark device as used */
+       ov511_devused |= 1 << nr;
+       ov->nr = nr;
+
        dev_info(&intf->dev, "Device at %s registered to minor %d\n",
                 ov->usb_path, ov->vdev->minor);
 
        usb_set_intfdata(intf, ov);
        if (ov_create_sysfs(ov->vdev)) {
                err("ov_create_sysfs failed");
+               ov511_devused &= ~(1 << nr);
+               mutex_unlock(&ov->lock);
                goto error;
        }
 
+       mutex_lock(&ov->lock);
+
        return 0;
 
 error:
@@ -5906,10 +5916,16 @@ ov51x_disconnect(struct usb_interface *intf)
 
        PDEBUG(3, "");
 
+       mutex_lock(&ov->lock);
        usb_set_intfdata (intf, NULL);
 
-       if (!ov)
+       if (!ov) {
+               mutex_unlock(&ov->lock);
                return;
+       }
+
+       /* Free device number */
+       ov511_devused &= ~(1 << ov->nr);
 
        if (ov->vdev)
                video_unregister_device(ov->vdev);
@@ -5927,6 +5943,7 @@ ov51x_disconnect(struct usb_interface *intf)
 
        ov->streaming = 0;
        ov51x_unlink_isoc(ov);
+       mutex_unlock(&ov->lock);
 
        ov->dev = NULL;
 
index 70d99e52329d53ff457d9d335982808e92171d8f..c450c92468da58c4dbb5e403d605d125faaf6054 100644 (file)
@@ -494,6 +494,9 @@ struct usb_ov511 {
        int has_decoder;        /* Device has a video decoder */
        int pal;                /* Device is designed for PAL resolution */
 
+       /* ov511 device number ID */
+       int nr;                 /* Stores a device number */
+
        /* I2C interface */
        struct mutex i2c_lock;    /* Protect I2C controller regs */
        unsigned char primary_i2c_slave;  /* I2C write id of sensor */
index 1cb6a260e8b00056940c4200348ce9461cd1e16c..336a20eded0f25e5a294a93bf1294ec7249222fa 100644 (file)
@@ -71,6 +71,7 @@ static const struct pvr2_device_desc pvr2_device_29xxx = {
                .flag_has_svideo = !0,
                .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
                .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+               .ir_scheme = PVR2_IR_SCHEME_29XXX,
 };
 
 
@@ -284,6 +285,11 @@ static struct tda10048_config hauppauge_tda10048_config = {
        .output_mode    = TDA10048_PARALLEL_OUTPUT,
        .fwbulkwritelen = TDA10048_BULKWRITE_50,
        .inversion      = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_3300,
+       .dtv7_if_freq_khz = TDA10048_IF_3800,
+       .dtv8_if_freq_khz = TDA10048_IF_4300,
+       .clk_freq_khz   = TDA10048_CLK_16000,
+       .disable_gate_access = 1,
 };
 
 static struct tda829x_config tda829x_no_probe = {
index 3e553389cbc34c4c8f94c3d2db7be1d8afd84c32..ea04ecf8aa39a0a33d291c5726f8fc52d3526fce 100644 (file)
@@ -69,6 +69,7 @@ struct pvr2_string_table {
 #define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
 #define PVR2_ROUTING_SCHEME_GOTVIEW 1
 #define PVR2_ROUTING_SCHEME_ONAIR 2
+#define PVR2_ROUTING_SCHEME_AV400 3
 
 #define PVR2_DIGITAL_SCHEME_NONE 0
 #define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1
@@ -78,8 +79,10 @@ struct pvr2_string_table {
 #define PVR2_LED_SCHEME_HAUPPAUGE 1
 
 #define PVR2_IR_SCHEME_NONE 0
-#define PVR2_IR_SCHEME_24XXX 1
-#define PVR2_IR_SCHEME_ZILOG 2
+#define PVR2_IR_SCHEME_24XXX 1 /* FX2-controlled IR */
+#define PVR2_IR_SCHEME_ZILOG 2 /* HVR-1950 style (must be taken out of reset) */
+#define PVR2_IR_SCHEME_24XXX_MCE 3 /* 24xxx MCE device */
+#define PVR2_IR_SCHEME_29XXX 4 /* Original 29xxx device */
 
 /* This describes a particular hardware type (except for the USB device ID
    which must live in a separate structure due to environmental
@@ -162,19 +165,9 @@ struct pvr2_device_desc {
           ensure that it is found. */
        unsigned int flag_has_wm8775:1;
 
-       /* Indicate any specialized IR scheme that might need to be
-          supported by this driver.  If not set, then it is assumed that
-          IR can work without help from the driver (which is frequently
-          the case).  This is otherwise set to one of
-          PVR2_IR_SCHEME_xxxx.  For "xxxx", the value "24XXX" indicates a
-          Hauppauge 24xxx class device which has an FPGA-hosted IR
-          receiver that can only be reached via FX2 command codes.  In
-          that case the pvrusb2 driver will emulate the behavior of the
-          older 29xxx device's IR receiver (a "virtual" I2C chip) in terms
-          of those command codes.  For the value "ZILOG", we're dealing
-          with an IR chip that must be taken out of reset via another FX2
-          command code (which is the case for HVR-1950 devices). */
-       unsigned int ir_scheme:2;
+       /* Indicate IR scheme of hardware.  If not set, then it is assumed
+          that IR can work without any help from the driver. */
+       unsigned int ir_scheme:3;
 
        /* These bits define which kinds of sources the device can handle.
           Note: Digital tuner presence is inferred by the
index 5d75eb5211b1a774067b34338c41a153a29aef45..5b152ff20bd0a3d94ad3dc9045538a2187db3422 100644 (file)
@@ -200,6 +200,9 @@ struct pvr2_hdw {
        int i2c_cx25840_hack_state;
        int i2c_linked;
 
+       /* IR related */
+       unsigned int ir_scheme_active; /* IR scheme as seen from the outside */
+
        /* Frequency table */
        unsigned int freqTable[FREQTABLE_SIZE];
        unsigned int freqProgSlot;
index add3395d324804aa974afb992003d374fcd09f21..0c745b142fb73999c77067aa83ff7eccd29d8bbf 100644 (file)
@@ -142,6 +142,15 @@ static const unsigned char *module_i2c_addresses[] = {
 };
 
 
+static const char *ir_scheme_names[] = {
+       [PVR2_IR_SCHEME_NONE] = "none",
+       [PVR2_IR_SCHEME_29XXX] = "29xxx",
+       [PVR2_IR_SCHEME_24XXX] = "24xxx (29xxx emulation)",
+       [PVR2_IR_SCHEME_24XXX_MCE] = "24xxx (MCE device)",
+       [PVR2_IR_SCHEME_ZILOG] = "Zilog",
+};
+
+
 /* Define the list of additional controls we'll dynamically construct based
    on query of the cx2341x module. */
 struct pvr2_mpeg_ids {
@@ -2170,7 +2179,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
        }
 
        /* Take the IR chip out of reset, if appropriate */
-       if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_ZILOG) {
+       if (hdw->ir_scheme_active == PVR2_IR_SCHEME_ZILOG) {
                pvr2_issue_simple_cmd(hdw,
                                      FX2CMD_HCW_ZILOG_RESET |
                                      (1 << 8) |
@@ -2451,6 +2460,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                                GFP_KERNEL);
        if (!hdw->controls) goto fail;
        hdw->hdw_desc = hdw_desc;
+       hdw->ir_scheme_active = hdw->hdw_desc->ir_scheme;
        for (idx = 0; idx < hdw->control_cnt; idx++) {
                cptr = hdw->controls + idx;
                cptr->hdw = hdw;
@@ -4809,6 +4819,12 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
                        stats.buffers_processed,
                        stats.buffers_failed);
        }
+       case 6: {
+               unsigned int id = hdw->ir_scheme_active;
+               return scnprintf(buf, acnt, "ir scheme: id=%d %s", id,
+                                (id >= ARRAY_SIZE(ir_scheme_names) ?
+                                 "?" : ir_scheme_names[id]));
+       }
        default: break;
        }
        return 0;
@@ -4825,65 +4841,35 @@ static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw,
        unsigned int tcnt = 0;
        unsigned int ccnt;
        struct i2c_client *client;
-       struct list_head *item;
-       void *cd;
        const char *p;
        unsigned int id;
 
-       ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers:");
+       ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers and I2C clients:\n");
        tcnt += ccnt;
        v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
                id = sd->grp_id;
                p = NULL;
                if (id < ARRAY_SIZE(module_names)) p = module_names[id];
                if (p) {
-                       ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s", p);
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "  %s:", p);
                        tcnt += ccnt;
                } else {
                        ccnt = scnprintf(buf + tcnt, acnt - tcnt,
-                                        " (unknown id=%u)", id);
+                                        "  (unknown id=%u):", id);
                        tcnt += ccnt;
                }
-       }
-       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
-       tcnt += ccnt;
-
-       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "I2C clients:\n");
-       tcnt += ccnt;
-
-       mutex_lock(&hdw->i2c_adap.clist_lock);
-       list_for_each(item, &hdw->i2c_adap.clients) {
-               client = list_entry(item, struct i2c_client, list);
-               ccnt = scnprintf(buf + tcnt, acnt - tcnt,
-                                "  %s: i2c=%02x", client->name, client->addr);
-               tcnt += ccnt;
-               cd = i2c_get_clientdata(client);
-               v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
-                       if (cd == sd) {
-                               id = sd->grp_id;
-                               p = NULL;
-                               if (id < ARRAY_SIZE(module_names)) {
-                                       p = module_names[id];
-                               }
-                               if (p) {
-                                       ccnt = scnprintf(buf + tcnt,
-                                                        acnt - tcnt,
-                                                        " subdev=%s", p);
-                                       tcnt += ccnt;
-                               } else {
-                                       ccnt = scnprintf(buf + tcnt,
-                                                        acnt - tcnt,
-                                                        " subdev= id %u)",
-                                                        id);
-                                       tcnt += ccnt;
-                               }
-                               break;
-                       }
+               client = v4l2_get_subdevdata(sd);
+               if (client) {
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+                                        " %s @ %02x\n", client->name,
+                                        client->addr);
+                       tcnt += ccnt;
+               } else {
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+                                        " no i2c client\n");
+                       tcnt += ccnt;
                }
-               ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
-               tcnt += ccnt;
        }
-       mutex_unlock(&hdw->i2c_adap.clist_lock);
        return tcnt;
 }
 
index 9af282f9e76544b8206aecc40505ab38a431e1bb..610bd848df246537ddd3b65da677c0643a4d8037 100644 (file)
@@ -42,6 +42,18 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
 module_param_array(ir_mode, int, NULL, 0444);
 MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
 
+static int pvr2_disable_ir_video;
+module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video,
+                  int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(disable_autoload_ir_video,
+                "1=do not try to autoload ir_video IR receiver");
+
+/* Mapping of IR schemes to known I2C addresses - if any */
+static const unsigned char ir_video_addresses[] = {
+       [PVR2_IR_SCHEME_29XXX] = 0x18,
+       [PVR2_IR_SCHEME_24XXX] = 0x18,
+};
+
 static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
                          u8 i2c_addr,      /* I2C address we're talking to */
                          u8 *data,         /* Data to write */
@@ -559,6 +571,31 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
        printk(KERN_INFO "%s: i2c scan done.\n", hdw->name);
 }
 
+static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
+{
+       struct i2c_board_info info;
+       unsigned char addr = 0;
+       if (pvr2_disable_ir_video) {
+               pvr2_trace(PVR2_TRACE_INFO,
+                          "Automatic binding of ir_video has been disabled.");
+               return;
+       }
+       if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) {
+               addr = ir_video_addresses[hdw->ir_scheme_active];
+       }
+       if (!addr) {
+               /* The device either doesn't support I2C-based IR or we
+                  don't know (yet) how to operate IR on the device. */
+               return;
+       }
+       pvr2_trace(PVR2_TRACE_INFO,
+                  "Binding ir_video to i2c address 0x%02x.", addr);
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+       info.addr = addr;
+       i2c_new_device(&hdw->i2c_adap, &info);
+}
+
 void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
 {
        unsigned int idx;
@@ -574,7 +611,9 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
                printk(KERN_INFO "%s: IR disabled\n",hdw->name);
                hdw->i2c_func[0x18] = i2c_black_hole;
        } else if (ir_mode[hdw->unit_number] == 1) {
-               if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_24XXX) {
+               if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) {
+                       /* Set up translation so that our IR looks like a
+                          29xxx device */
                        hdw->i2c_func[0x18] = i2c_24xxx_ir;
                }
        }
@@ -597,15 +636,23 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
        i2c_add_adapter(&hdw->i2c_adap);
        if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
                /* Probe for a different type of IR receiver on this
-                  device.  If present, disable the emulated IR receiver. */
+                  device.  This is really the only way to differentiate
+                  older 24xxx devices from 24xxx variants that include an
+                  IR blaster.  If the IR blaster is present, the IR
+                  receiver is part of that chip and thus we must disable
+                  the emulated IR receiver. */
                if (do_i2c_probe(hdw, 0x71)) {
                        pvr2_trace(PVR2_TRACE_INFO,
                                   "Device has newer IR hardware;"
                                   " disabling unneeded virtual IR device");
                        hdw->i2c_func[0x18] = NULL;
+                       /* Remember that this is a different device... */
+                       hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE;
                }
        }
        if (i2c_scan) do_i2c_scan(hdw);
+
+       pvr2_i2c_register_ir(hdw);
 }
 
 void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
index 9e0f2b07b93b277bed1123220b77eeb222956a02..2d8825e5b1bef5f3e319fa7dc8a1df4d3629a856 100644 (file)
@@ -90,7 +90,7 @@ static struct v4l2_capability pvr_capability ={
        .driver         = "pvrusb2",
        .card           = "Hauppauge WinTV pvr-usb2",
        .bus_info       = "usb",
-       .version        = KERNEL_VERSION(0,8,0),
+       .version        = KERNEL_VERSION(0, 9, 0),
        .capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
                           V4L2_CAP_READWRITE),
@@ -267,7 +267,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(&tmp,0,sizeof(tmp));
                tmp.index = vi->index;
                ret = 0;
-               if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
+               if (vi->index >= fh->input_cnt) {
                        ret = -EINVAL;
                        break;
                }
@@ -331,7 +331,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        case VIDIOC_S_INPUT:
        {
                struct v4l2_input *vi = (struct v4l2_input *)arg;
-               if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
+               if (vi->index >= fh->input_cnt) {
                        ret = -ERANGE;
                        break;
                }
index 7c542caf248e40ff1647bf0b4c6d6345448affd5..db25c3034c11be4e7deb4cc98bf41006b4e860f7 100644 (file)
@@ -601,7 +601,7 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down)
 
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
        if (pdev->button_dev) {
-               input_report_key(pdev->button_dev, BTN_0, down);
+               input_report_key(pdev->button_dev, KEY_CAMERA, down);
                input_sync(pdev->button_dev);
        }
 #endif
@@ -1783,7 +1783,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                return -ENOMEM;
        }
        memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
-       pdev->vdev->parent = &(udev->dev);
+       pdev->vdev->parent = &intf->dev;
        strcpy(pdev->vdev->name, name);
        video_set_drvdata(pdev->vdev, pdev);
 
@@ -1847,7 +1847,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        usb_to_input_id(pdev->udev, &pdev->button_dev->id);
        pdev->button_dev->dev.parent = &pdev->udev->dev;
        pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
-       pdev->button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+       pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
 
        rc = input_register_device(pdev->button_dev);
        if (rc) {
index bc0a464295c59d511128b8526c445419c808e7b3..2876ce08451095fc275b151c129529744673ef93 100644 (file)
@@ -1107,7 +1107,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                                return -EINVAL;
                        if (buf->memory != V4L2_MEMORY_MMAP)
                                return -EINVAL;
-                       if (buf->index < 0 || buf->index >= pwc_mbufs)
+                       if (buf->index >= pwc_mbufs)
                                return -EINVAL;
 
                        buf->flags |= V4L2_BUF_FLAG_QUEUED;
index c639845460fff8df6a327bf1f7e21ebbb954ac34..f60de40fd21f79d17274dc0fe3769a84639d9f6a 100644 (file)
@@ -202,7 +202,7 @@ struct pxa_buffer {
 };
 
 struct pxa_camera_dev {
-       struct device           *dev;
+       struct soc_camera_host  soc_host;
        /* PXA27x is only supposed to handle one camera on its Quick Capture
         * interface. If anyone ever builds hardware to enable more than
         * one camera, they will have to modify this driver too */
@@ -261,7 +261,6 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
 {
        struct soc_camera_device *icd = vq->priv_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       struct pxa_camera_dev *pcdev = ici->priv;
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
        int i;
 
@@ -278,7 +277,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
 
        for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
                if (buf->dmas[i].sg_cpu)
-                       dma_free_coherent(pcdev->dev, buf->dmas[i].sg_size,
+                       dma_free_coherent(ici->dev, buf->dmas[i].sg_size,
                                          buf->dmas[i].sg_cpu,
                                          buf->dmas[i].sg_dma);
                buf->dmas[i].sg_cpu = NULL;
@@ -338,14 +337,14 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
        int dma_len = 0, xfer_len = 0;
 
        if (pxa_dma->sg_cpu)
-               dma_free_coherent(pcdev->dev, pxa_dma->sg_size,
+               dma_free_coherent(pcdev->soc_host.dev, pxa_dma->sg_size,
                                  pxa_dma->sg_cpu, pxa_dma->sg_dma);
 
        sglen = calculate_dma_sglen(*sg_first, dma->sglen,
                                    *sg_first_ofs, size);
 
        pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
-       pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size,
+       pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->soc_host.dev, pxa_dma->sg_size,
                                             &pxa_dma->sg_dma, GFP_KERNEL);
        if (!pxa_dma->sg_cpu)
                return -ENOMEM;
@@ -353,7 +352,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
        pxa_dma->sglen = sglen;
        offset = *sg_first_ofs;
 
-       dev_dbg(pcdev->dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
+       dev_dbg(pcdev->soc_host.dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
                *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
 
 
@@ -376,7 +375,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
                pxa_dma->sg_cpu[i].ddadr =
                        pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
 
-               dev_vdbg(pcdev->dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
+               dev_vdbg(pcdev->soc_host.dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
                         pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
                         sg_dma_address(sg) + offset, xfer_len);
                offset = 0;
@@ -488,7 +487,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
                                           &sg, &next_ofs);
                if (ret) {
-                       dev_err(pcdev->dev,
+                       dev_err(pcdev->soc_host.dev,
                                "DMA initialization for Y/RGB failed\n");
                        goto fail;
                }
@@ -498,7 +497,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                        ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
                                                   size_u, &sg, &next_ofs);
                if (ret) {
-                       dev_err(pcdev->dev,
+                       dev_err(pcdev->soc_host.dev,
                                "DMA initialization for U failed\n");
                        goto fail_u;
                }
@@ -508,7 +507,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                        ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
                                                   size_v, &sg, &next_ofs);
                if (ret) {
-                       dev_err(pcdev->dev,
+                       dev_err(pcdev->soc_host.dev,
                                "DMA initialization for V failed\n");
                        goto fail_v;
                }
@@ -522,10 +521,10 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
        return 0;
 
 fail_v:
-       dma_free_coherent(pcdev->dev, buf->dmas[1].sg_size,
+       dma_free_coherent(pcdev->soc_host.dev, buf->dmas[1].sg_size,
                          buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
 fail_u:
-       dma_free_coherent(pcdev->dev, buf->dmas[0].sg_size,
+       dma_free_coherent(pcdev->soc_host.dev, buf->dmas[0].sg_size,
                          buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
 fail:
        free_buffer(vq, buf);
@@ -549,7 +548,7 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev)
        active = pcdev->active;
 
        for (i = 0; i < pcdev->channels; i++) {
-               dev_dbg(pcdev->dev, "%s (channel=%d) ddadr=%08x\n", __func__,
+               dev_dbg(pcdev->soc_host.dev, "%s (channel=%d) ddadr=%08x\n", __func__,
                        i, active->dmas[i].sg_dma);
                DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma;
                DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
@@ -561,7 +560,7 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev)
        int i;
 
        for (i = 0; i < pcdev->channels; i++) {
-               dev_dbg(pcdev->dev, "%s (channel=%d)\n", __func__, i);
+               dev_dbg(pcdev->soc_host.dev, "%s (channel=%d)\n", __func__, i);
                DCSR(pcdev->dma_chans[i]) = 0;
        }
 }
@@ -597,7 +596,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev)
 {
        unsigned long cicr0, cifr;
 
-       dev_dbg(pcdev->dev, "%s\n", __func__);
+       dev_dbg(pcdev->soc_host.dev, "%s\n", __func__);
        /* Reset the FIFOs */
        cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
        __raw_writel(cifr, pcdev->base + CIFR);
@@ -617,7 +616,7 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev)
        __raw_writel(cicr0, pcdev->base + CICR0);
 
        pcdev->active = NULL;
-       dev_dbg(pcdev->dev, "%s\n", __func__);
+       dev_dbg(pcdev->soc_host.dev, "%s\n", __func__);
 }
 
 static void pxa_videobuf_queue(struct videobuf_queue *vq,
@@ -686,7 +685,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
        do_gettimeofday(&vb->ts);
        vb->field_count++;
        wake_up(&vb->done);
-       dev_dbg(pcdev->dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb);
+       dev_dbg(pcdev->soc_host.dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb);
 
        if (list_empty(&pcdev->capture)) {
                pxa_camera_stop_capture(pcdev);
@@ -722,7 +721,7 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
        for (i = 0; i < pcdev->channels; i++)
                if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP)
                        is_dma_stopped = 0;
-       dev_dbg(pcdev->dev, "%s : top queued buffer=%p, dma_stopped=%d\n",
+       dev_dbg(pcdev->soc_host.dev, "%s : top queued buffer=%p, dma_stopped=%d\n",
                __func__, pcdev->active, is_dma_stopped);
        if (pcdev->active && is_dma_stopped)
                pxa_camera_start_capture(pcdev);
@@ -747,12 +746,12 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
                overrun |= CISR_IFO_1 | CISR_IFO_2;
 
        if (status & DCSR_BUSERR) {
-               dev_err(pcdev->dev, "DMA Bus Error IRQ!\n");
+               dev_err(pcdev->soc_host.dev, "DMA Bus Error IRQ!\n");
                goto out;
        }
 
        if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) {
-               dev_err(pcdev->dev, "Unknown DMA IRQ source, "
+               dev_err(pcdev->soc_host.dev, "Unknown DMA IRQ source, "
                        "status: 0x%08x\n", status);
                goto out;
        }
@@ -776,7 +775,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
        buf = container_of(vb, struct pxa_buffer, vb);
        WARN_ON(buf->inwork || list_empty(&vb->queue));
 
-       dev_dbg(pcdev->dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
+       dev_dbg(pcdev->soc_host.dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
                __func__, channel, status & DCSR_STARTINTR ? "SOF " : "",
                status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel));
 
@@ -787,7 +786,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
                 */
                if (camera_status & overrun &&
                    !list_is_last(pcdev->capture.next, &pcdev->capture)) {
-                       dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n",
+                       dev_dbg(pcdev->soc_host.dev, "FIFO overrun! CISR: %x\n",
                                camera_status);
                        pxa_camera_stop_capture(pcdev);
                        pxa_camera_start_capture(pcdev);
@@ -854,7 +853,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
        /* mclk <= ciclk / 4 (27.4.2) */
        if (mclk > lcdclk / 4) {
                mclk = lcdclk / 4;
-               dev_warn(pcdev->dev, "Limiting master clock to %lu\n", mclk);
+               dev_warn(pcdev->soc_host.dev, "Limiting master clock to %lu\n", mclk);
        }
 
        /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
@@ -864,7 +863,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
        if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
                pcdev->mclk = lcdclk / (2 * (div + 1));
 
-       dev_dbg(pcdev->dev, "LCD clock %luHz, target freq %luHz, "
+       dev_dbg(pcdev->soc_host.dev, "LCD clock %luHz, target freq %luHz, "
                "divisor %u\n", lcdclk, mclk, div);
 
        return div;
@@ -884,12 +883,12 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
        struct pxacamera_platform_data *pdata = pcdev->pdata;
        u32 cicr4 = 0;
 
-       dev_dbg(pcdev->dev, "Registered platform device at %p data %p\n",
+       dev_dbg(pcdev->soc_host.dev, "Registered platform device at %p data %p\n",
                pcdev, pdata);
 
        if (pdata && pdata->init) {
-               dev_dbg(pcdev->dev, "%s: Init gpios\n", __func__);
-               pdata->init(pcdev->dev);
+               dev_dbg(pcdev->soc_host.dev, "%s: Init gpios\n", __func__);
+               pdata->init(pcdev->soc_host.dev);
        }
 
        /* disable all interrupts */
@@ -931,7 +930,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
        struct videobuf_buffer *vb;
 
        status = __raw_readl(pcdev->base + CISR);
-       dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status);
+       dev_dbg(pcdev->soc_host.dev, "Camera interrupt status 0x%lx\n", status);
 
        if (!status)
                return IRQ_NONE;
@@ -1259,7 +1258,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(ici->dev, "Providing format %s using %s\n",
                                pxa_camera_formats[0].name,
                                icd->formats[idx].name);
                }
@@ -1274,7 +1273,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s packed\n",
+                       dev_dbg(ici->dev, "Providing format %s packed\n",
                                icd->formats[idx].name);
                }
                break;
@@ -1286,7 +1285,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = icd->formats[idx].depth;
                        xlate++;
-                       dev_dbg(&ici->dev,
+                       dev_dbg(ici->dev,
                                "Providing format %s in pass-through mode\n",
                                icd->formats[idx].name);
                }
@@ -1315,11 +1314,11 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
        icd->sense = NULL;
 
        if (ret < 0) {
-               dev_warn(&ici->dev, "Failed to crop to %ux%u@%u:%u\n",
+               dev_warn(ici->dev, "Failed to crop to %ux%u@%u:%u\n",
                         rect->width, rect->height, rect->left, rect->top);
        } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
                if (sense.pixel_clock > sense.pixel_clock_max) {
-                       dev_err(&ici->dev,
+                       dev_err(ici->dev,
                                "pixel clock %lu set by the camera too high!",
                                sense.pixel_clock);
                        return -EIO;
@@ -1347,7 +1346,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+               dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
                return -EINVAL;
        }
 
@@ -1363,11 +1362,11 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
        icd->sense = NULL;
 
        if (ret < 0) {
-               dev_warn(&ici->dev, "Failed to configure for format %x\n",
+               dev_warn(ici->dev, "Failed to configure for format %x\n",
                         pix->pixelformat);
        } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
                if (sense.pixel_clock > sense.pixel_clock_max) {
-                       dev_err(&ici->dev,
+                       dev_err(ici->dev,
                                "pixel clock %lu set by the camera too high!",
                                sense.pixel_clock);
                        return -EIO;
@@ -1395,7 +1394,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -1552,13 +1551,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .set_bus_param  = pxa_camera_set_bus_param,
 };
 
-/* Should be allocated dynamically too, but we have only one. */
-static struct soc_camera_host pxa_soc_camera_host = {
-       .drv_name               = PXA_CAM_DRV_NAME,
-       .ops                    = &pxa_soc_camera_host_ops,
-};
-
-static int pxa_camera_probe(struct platform_device *pdev)
+static int __devinit pxa_camera_probe(struct platform_device *pdev)
 {
        struct pxa_camera_dev *pcdev;
        struct resource *res;
@@ -1586,7 +1579,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
                goto exit_kfree;
        }
 
-       dev_set_drvdata(&pdev->dev, pcdev);
        pcdev->res = res;
 
        pcdev->pdata = pdev->dev.platform_data;
@@ -1607,7 +1599,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
                pcdev->mclk = 20000000;
        }
 
-       pcdev->dev = &pdev->dev;
        pcdev->mclk_divisor = mclk_get_divisor(pcdev);
 
        INIT_LIST_HEAD(&pcdev->capture);
@@ -1616,13 +1607,13 @@ static int pxa_camera_probe(struct platform_device *pdev)
        /*
         * Request the regions.
         */
-       if (!request_mem_region(res->start, res->end - res->start + 1,
+       if (!request_mem_region(res->start, resource_size(res),
                                PXA_CAM_DRV_NAME)) {
                err = -EBUSY;
                goto exit_clk;
        }
 
-       base = ioremap(res->start, res->end - res->start + 1);
+       base = ioremap(res->start, resource_size(res));
        if (!base) {
                err = -ENOMEM;
                goto exit_release;
@@ -1634,29 +1625,29 @@ static int pxa_camera_probe(struct platform_device *pdev)
        err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
                              pxa_camera_dma_irq_y, pcdev);
        if (err < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for Y\n");
+               dev_err(&pdev->dev, "Can't request DMA for Y\n");
                goto exit_iounmap;
        }
        pcdev->dma_chans[0] = err;
-       dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
+       dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
 
        err = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
                              pxa_camera_dma_irq_u, pcdev);
        if (err < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for U\n");
+               dev_err(&pdev->dev, "Can't request DMA for U\n");
                goto exit_free_dma_y;
        }
        pcdev->dma_chans[1] = err;
-       dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
+       dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
 
        err = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
                              pxa_camera_dma_irq_v, pcdev);
        if (err < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for V\n");
+               dev_err(&pdev->dev, "Can't request DMA for V\n");
                goto exit_free_dma_u;
        }
        pcdev->dma_chans[2] = err;
-       dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
+       dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
 
        DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
        DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
@@ -1666,14 +1657,17 @@ static int pxa_camera_probe(struct platform_device *pdev)
        err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
                          pcdev);
        if (err) {
-               dev_err(pcdev->dev, "Camera interrupt register failed \n");
+               dev_err(&pdev->dev, "Camera interrupt register failed \n");
                goto exit_free_dma;
        }
 
-       pxa_soc_camera_host.priv        = pcdev;
-       pxa_soc_camera_host.dev.parent  = &pdev->dev;
-       pxa_soc_camera_host.nr          = pdev->id;
-       err = soc_camera_host_register(&pxa_soc_camera_host);
+       pcdev->soc_host.drv_name        = PXA_CAM_DRV_NAME;
+       pcdev->soc_host.ops             = &pxa_soc_camera_host_ops;
+       pcdev->soc_host.priv            = pcdev;
+       pcdev->soc_host.dev             = &pdev->dev;
+       pcdev->soc_host.nr              = pdev->id;
+
+       err = soc_camera_host_register(&pcdev->soc_host);
        if (err)
                goto exit_free_irq;
 
@@ -1690,7 +1684,7 @@ exit_free_dma_y:
 exit_iounmap:
        iounmap(base);
 exit_release:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 exit_clk:
        clk_put(pcdev->clk);
 exit_kfree:
@@ -1701,7 +1695,9 @@ exit:
 
 static int __devexit pxa_camera_remove(struct platform_device *pdev)
 {
-       struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct pxa_camera_dev *pcdev = container_of(soc_host,
+                                       struct pxa_camera_dev, soc_host);
        struct resource *res;
 
        clk_put(pcdev->clk);
@@ -1711,12 +1707,12 @@ static int __devexit pxa_camera_remove(struct platform_device *pdev)
        pxa_free_dma(pcdev->dma_chans[2]);
        free_irq(pcdev->irq, pcdev);
 
-       soc_camera_host_unregister(&pxa_soc_camera_host);
+       soc_camera_host_unregister(soc_host);
 
        iounmap(pcdev->base);
 
        res = pcdev->res;
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        kfree(pcdev);
 
@@ -1730,11 +1726,11 @@ static struct platform_driver pxa_camera_driver = {
                .name   = PXA_CAM_DRV_NAME,
        },
        .probe          = pxa_camera_probe,
-       .remove         = __exit_p(pxa_camera_remove),
+       .remove         = __devexit_p(pxa_camera_remove),
 };
 
 
-static int __devinit pxa_camera_init(void)
+static int __init pxa_camera_init(void)
 {
        return platform_driver_register(&pxa_camera_driver);
 }
index 30f4698be90a5a9555426b2732f7dfc268256fbb..6be845ccc7d7e7412f97b2e65c32e6cd3deb091e 100644 (file)
@@ -77,6 +77,8 @@
 #define MAX_CHANNELS           4
 #define S2255_MARKER_FRAME     0x2255DA4AL
 #define S2255_MARKER_RESPONSE  0x2255ACACL
+#define S2255_RESPONSE_SETMODE  0x01
+#define S2255_RESPONSE_FW       0x10
 #define S2255_USB_XFER_SIZE    (16 * 1024)
 #define MAX_CHANNELS           4
 #define MAX_PIPE_BUFFERS       1
 #define SCALE_4CIFS    1       /* 640x480(NTSC) or 704x576(PAL) */
 #define SCALE_2CIFS    2       /* 640x240(NTSC) or 704x288(PAL) */
 #define SCALE_1CIFS    3       /* 320x240(NTSC) or 352x288(PAL) */
+/* SCALE_4CIFSI is the 2 fields interpolated into one */
+#define SCALE_4CIFSI   4       /* 640x480(NTSC) or 704x576(PAL) high quality */
 
 #define COLOR_YUVPL    1       /* YUV planar */
 #define COLOR_YUVPK    2       /* YUV packed */
@@ -178,9 +182,6 @@ struct s2255_bufferi {
 
 struct s2255_dmaqueue {
        struct list_head        active;
-       /* thread for acquisition */
-       struct task_struct      *kthread;
-       int                     frame;
        struct s2255_dev        *dev;
        int                     channel;
 };
@@ -210,16 +211,11 @@ struct s2255_pipeinfo {
        u32 max_transfer_size;
        u32 cur_transfer_size;
        u8 *transfer_buffer;
-       u32 transfer_flags;;
        u32 state;
-       u32 prev_state;
-       u32 urb_size;
        void *stream_urb;
        void *dev;      /* back pointer to s2255_dev struct*/
        u32 err_count;
-       u32 buf_index;
        u32 idx;
-       u32 priority_set;
 };
 
 struct s2255_fmt; /*forward declaration */
@@ -239,13 +235,13 @@ struct s2255_dev {
        struct list_head        s2255_devlist;
        struct timer_list       timer;
        struct s2255_fw *fw_data;
-       int                     board_num;
-       int                     is_open;
        struct s2255_pipeinfo   pipes[MAX_PIPE_BUFFERS];
        struct s2255_bufferi            buffer[MAX_CHANNELS];
        struct s2255_mode       mode[MAX_CHANNELS];
        /* jpeg compression */
        struct v4l2_jpegcompression jc[MAX_CHANNELS];
+       /* capture parameters (for high quality mode full size) */
+       struct v4l2_captureparm cap_parm[MAX_CHANNELS];
        const struct s2255_fmt  *cur_fmt[MAX_CHANNELS];
        int                     cur_frame[MAX_CHANNELS];
        int                     last_frame[MAX_CHANNELS];
@@ -297,9 +293,10 @@ struct s2255_fh {
        int                     resources[MAX_CHANNELS];
 };
 
-#define CUR_USB_FWVER  774     /* current cypress EEPROM firmware version */
+/* current cypress EEPROM firmware version */
+#define S2255_CUR_USB_FWVER    ((3 << 8) | 6)
 #define S2255_MAJOR_VERSION    1
-#define S2255_MINOR_VERSION    13
+#define S2255_MINOR_VERSION    14
 #define S2255_RELEASE          0
 #define S2255_VERSION          KERNEL_VERSION(S2255_MAJOR_VERSION, \
                                               S2255_MINOR_VERSION, \
@@ -1027,9 +1024,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        fh->type = f->type;
        norm = norm_minw(fh->dev->vdev[fh->channel]);
        if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) {
-               if (fh->height > norm_minh(fh->dev->vdev[fh->channel]))
-                       fh->mode.scale = SCALE_4CIFS;
-               else
+               if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) {
+                       if (fh->dev->cap_parm[fh->channel].capturemode &
+                           V4L2_MODE_HIGHQUALITY) {
+                               fh->mode.scale = SCALE_4CIFSI;
+                               dprintk(2, "scale 4CIFSI\n");
+                       } else {
+                               fh->mode.scale = SCALE_4CIFS;
+                               dprintk(2, "scale 4CIFS\n");
+                       }
+               } else
                        fh->mode.scale = SCALE_2CIFS;
 
        } else {
@@ -1130,6 +1134,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
        if (mode->format == FORMAT_NTSC) {
                switch (mode->scale) {
                case SCALE_4CIFS:
+               case SCALE_4CIFSI:
                        linesPerFrame = NUM_LINES_4CIFS_NTSC * 2;
                        pixelsPerLine = LINE_SZ_4CIFS_NTSC;
                        break;
@@ -1147,6 +1152,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
        } else if (mode->format == FORMAT_PAL) {
                switch (mode->scale) {
                case SCALE_4CIFS:
+               case SCALE_4CIFSI:
                        linesPerFrame = NUM_LINES_4CIFS_PAL * 2;
                        pixelsPerLine = LINE_SZ_4CIFS_PAL;
                        break;
@@ -1502,6 +1508,33 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
        dprintk(2, "setting jpeg quality %d\n", jc->quality);
        return 0;
 }
+
+static int vidioc_g_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *sp)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
+       dprintk(2, "getting parm %d\n", sp->parm.capture.capturemode);
+       return 0;
+}
+
+static int vidioc_s_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *sp)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+
+       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       dev->cap_parm[fh->channel].capturemode = sp->parm.capture.capturemode;
+       dprintk(2, "setting param capture mode %d\n",
+               sp->parm.capture.capturemode);
+       return 0;
+}
 static int s2255_open(struct file *file)
 {
        int minor = video_devdata(file)->minor;
@@ -1793,6 +1826,8 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
 #endif
        .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
        .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
+       .vidioc_s_parm = vidioc_s_parm,
+       .vidioc_g_parm = vidioc_g_parm,
 };
 
 static struct video_device template = {
@@ -1818,7 +1853,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                INIT_LIST_HEAD(&dev->vidq[i].active);
                dev->vidq[i].dev = dev;
                dev->vidq[i].channel = i;
-               dev->vidq[i].kthread = NULL;
                /* register 4 video devices */
                dev->vdev[i] = video_device_alloc();
                memcpy(dev->vdev[i], &template, sizeof(struct video_device));
@@ -1839,7 +1873,9 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                        return ret;
                }
        }
-       printk(KERN_INFO "Sensoray 2255 V4L driver\n");
+       printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
+              S2255_MAJOR_VERSION,
+              S2255_MINOR_VERSION);
        return ret;
 }
 
@@ -1929,14 +1965,14 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                                if (!(cc >= 0 && cc < MAX_CHANNELS))
                                        break;
                                switch (pdword[2]) {
-                               case 0x01:
+                               case S2255_RESPONSE_SETMODE:
                                        /* check if channel valid */
                                        /* set mode ready */
                                        dev->setmode_ready[cc] = 1;
                                        wake_up(&dev->wait_setmode[cc]);
                                        dprintk(5, "setmode ready %d\n", cc);
                                        break;
-                               case 0x10:
+                               case S2255_RESPONSE_FW:
 
                                        dev->chn_ready |= (1 << cc);
                                        if ((dev->chn_ready & 0x0f) != 0x0f)
@@ -2172,10 +2208,15 @@ static int s2255_board_init(struct s2255_dev *dev)
        /* query the firmware */
        fw_ver = s2255_get_fx2fw(dev);
 
-       printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver);
-       if (fw_ver < CUR_USB_FWVER)
+       printk(KERN_INFO "2255 usb firmware version %d.%d\n",
+              (fw_ver >> 8) & 0xff,
+              fw_ver & 0xff);
+
+       if (fw_ver < S2255_CUR_USB_FWVER)
                dev_err(&dev->udev->dev,
-                       "usb firmware not up to date %d\n", fw_ver);
+                       "usb firmware not up to date %d.%d\n",
+                       (fw_ver >> 8) & 0xff,
+                       fw_ver & 0xff);
 
        for (j = 0; j < MAX_CHANNELS; j++) {
                dev->b_acquire[j] = 0;
@@ -2240,8 +2281,10 @@ static void read_pipe_completion(struct urb *purb)
                return;
        }
        status = purb->status;
-       if (status != 0) {
-               dprintk(2, "read_pipe_completion: err\n");
+       /* if shutting down, do not resubmit, exit immediately */
+       if (status == -ESHUTDOWN) {
+               dprintk(2, "read_pipe_completion: err shutdown\n");
+               pipe_info->err_count++;
                return;
        }
 
@@ -2250,9 +2293,13 @@ static void read_pipe_completion(struct urb *purb)
                return;
        }
 
-       s2255_read_video_callback(dev, pipe_info);
+       if (status == 0)
+               s2255_read_video_callback(dev, pipe_info);
+       else {
+               pipe_info->err_count++;
+               dprintk(1, "s2255drv: failed URB %d\n", status);
+       }
 
-       pipe_info->err_count = 0;
        pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
        /* reuse urb */
        usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
@@ -2264,7 +2311,6 @@ static void read_pipe_completion(struct urb *purb)
        if (pipe_info->state != 0) {
                if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
                        dev_err(&dev->udev->dev, "error submitting urb\n");
-                       usb_free_urb(pipe_info->stream_urb);
                }
        } else {
                dprintk(2, "read pipe complete state 0\n");
@@ -2283,8 +2329,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
 
        for (i = 0; i < MAX_PIPE_BUFFERS; i++) {
                pipe_info->state = 1;
-               pipe_info->buf_index = (u32) i;
-               pipe_info->priority_set = 0;
+               pipe_info->err_count = 0;
                pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!pipe_info->stream_urb) {
                        dev_err(&dev->udev->dev,
@@ -2298,7 +2343,6 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
                                  pipe_info->cur_transfer_size,
                                  read_pipe_completion, pipe_info);
 
-               pipe_info->urb_size = sizeof(pipe_info->stream_urb);
                dprintk(4, "submitting URB %p\n", pipe_info->stream_urb);
                retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
                if (retval) {
@@ -2403,8 +2447,6 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
                        if (pipe_info->state == 0)
                                continue;
                        pipe_info->state = 0;
-                       pipe_info->prev_state = 1;
-
                }
        }
 
@@ -2542,7 +2584,9 @@ static int s2255_probe(struct usb_interface *interface,
        s2255_probe_v4l(dev);
        usb_reset_device(dev->udev);
        /* load 2255 board specific */
-       s2255_board_init(dev);
+       retval = s2255_board_init(dev);
+       if (retval)
+               goto error;
 
        dprintk(4, "before probe done %p\n", dev);
        spin_lock_init(&dev->slock);
index 0ba68987bfce96c541788eddd94d3a1d2bd334b7..5bcce092e804dff85d5598f2c940b417c36aa5b4 100644 (file)
@@ -44,6 +44,7 @@ config VIDEO_SAA7134_DVB
        select DVB_LNBP21 if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+       select DVB_TDA10048 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
        ---help---
index 3dbaa19a6d00d7f3dbc81f7769681c91d5fff41e..604158a8c2352b092774e388ea442814fef9ebf8 100644 (file)
@@ -3,8 +3,7 @@ saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o    \
                saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o    \
                saa7134-video.o saa7134-input.o
 
-obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
-                               saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134) +=  saa6752hs.o saa7134.o saa7134-empress.o
 
 obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
 
index fdb19449d269df0396cd7802455916119265e09e..06861b782b9529f503ac26102eb17fc2ddd68908 100644 (file)
@@ -1669,6 +1669,39 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = LINE1,
                },
        },
+       [SAA7134_BOARD_AVERMEDIA_CARDBUS_501] = {
+               /* Oldrich Jedlicka <oldium.pro@seznam.cz> */
+               .name           = "AVerMedia Cardbus TV/Radio (E501R)",
+               .audio_clock    = 0x187de7,
+               .tuner_type     = TUNER_ALPS_TSBE5_PAL,
+               .radio_type     = TUNER_TEA5767,
+               .tuner_addr     = 0x61,
+               .radio_addr     = 0x60,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x08000000,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+                       .gpio = 0x08000000,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+                       .gpio = 0x08000000,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+                       .gpio = 0x08000000,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x00000000,
+               },
+       },
        [SAA7134_BOARD_CINERGY400_CARDBUS] = {
                .name           = "Terratec Cinergy 400 mobile",
                .audio_clock    = 0x187de7,
@@ -3331,13 +3364,15 @@ struct saa7134_board saa7134_boards[] = {
                },
        },
        [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = {
-               .name           = "Hauppauge WinTV-HVR1110r3",
+               .name           = "Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid",
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_TDA8290,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tuner_config   = 3,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .ts_type        = SAA7134_MPEG_TS_SERIAL,
                .gpiomask       = 0x0800100, /* GPIO 21 is an INPUT */
                .inputs         = {{
                        .name = name_tv,
@@ -4006,7 +4041,7 @@ struct saa7134_board saa7134_boards[] = {
        [SAA7134_BOARD_BEHOLD_505FM] = {
                /*       Beholder Intl. Ltd. 2008      */
                /*Dmitry Belimov <d.belimov@gmail.com> */
-               .name           = "Beholder BeholdTV 505 FM/RDS",
+               .name           = "Beholder BeholdTV 505 FM",
                .audio_clock    = 0x00200000,
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
                .radio_type     = UNSET,
@@ -4014,6 +4049,40 @@ struct saa7134_board saa7134_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .gpiomask       = 0x00008000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE1,
+               },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_505RDS] = {
+               /*       Beholder Intl. Ltd. 2008      */
+               /*Dmitry Belimov <d.belimov@gmail.com> */
+               .name           = "Beholder BeholdTV 505 RDS",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x00008000,
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 3,
@@ -4040,7 +4109,7 @@ struct saa7134_board saa7134_boards[] = {
        [SAA7134_BOARD_BEHOLD_507_9FM] = {
                /*       Beholder Intl. Ltd. 2008      */
                /*Dmitry Belimov <d.belimov@gmail.com> */
-               .name           = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM",
+               .name           = "Beholder BeholdTV 507 FM / BeholdTV 509 FM",
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
                .radio_type     = UNSET,
@@ -4067,6 +4136,66 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = LINE2,
                },
        },
+       [SAA7134_BOARD_BEHOLD_507RDS_MK5] = {
+               /*       Beholder Intl. Ltd. 2008      */
+               /*Dmitry Belimov <d.belimov@gmail.com> */
+               .name           = "Beholder BeholdTV 507 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x00008000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+                       .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_507RDS_MK3] = {
+               /*       Beholder Intl. Ltd. 2008      */
+               /*Dmitry Belimov <d.belimov@gmail.com> */
+               .name           = "Beholder BeholdTV 507 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x00008000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+                       .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
        [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
                /*       Beholder Intl. Ltd. 2008      */
                /*Dmitry Belimov <d.belimov@gmail.com> */
@@ -4101,15 +4230,211 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x000A8000,
                },
        },
-       [SAA7134_BOARD_BEHOLD_607_9FM] = {
+       [SAA7134_BOARD_BEHOLD_607FM_MK3] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 607 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_609FM_MK3] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 609 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_607FM_MK5] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 607 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_609FM_MK5] = {
                /* Andrey Melnikoff <temnota@kmv.ru> */
-               .name           = "Beholder BeholdTV 607 / BeholdTV 609",
+               .name           = "Beholder BeholdTV 609 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_607RDS_MK3] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 607 RDS",
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_609RDS_MK3] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 609 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_607RDS_MK5] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 607 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_609RDS_MK5] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 609 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 3,
@@ -4133,6 +4458,7 @@ struct saa7134_board saa7134_boards[] = {
                /* Igor Kuznetsov <igk@igk.ru> */
                /* Andrey Melnikoff <temnota@kmv.ru> */
                /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+               /* Alexey Osipov <lion-simba@pridelands.ru> */
                .name           = "Beholder BeholdTV M6",
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
@@ -4207,10 +4533,10 @@ struct saa7134_board saa7134_boards[] = {
                /* Igor Kuznetsov <igk@igk.ru> */
                /* Andrey Melnikoff <temnota@kmv.ru> */
                /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+               /* Alexey Osipov <lion-simba@pridelands.ru> */
                .name           = "Beholder BeholdTV M6 Extra",
                .audio_clock    = 0x00187de7,
-               /* FIXME: Must be PHILIPS_FM1216ME_MK5*/
-               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -4465,7 +4791,6 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .mpeg           = SAA7134_MPEG_DVB,
                .inputs = {{
                        .name   = name_tv,
                        .vmux   = 3,
@@ -4753,6 +5078,44 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x01,
                },
        },
+       [SAA7134_BOARD_AVERMEDIA_STUDIO_507UA] = {
+               /* Andy Shevchenko <andy@smile.org.ua> */
+               .name           = "Avermedia AVerTV Studio 507UA",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* Should be MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x03,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+                       .gpio = 0x00,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+                       .gpio = 0x00,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+                       .gpio = 0x00,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x01,
+               },
+               .mute  = {
+                       .name = name_mute,
+                       .amux = LINE1,
+                       .gpio = 0x00,
+               },
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -5027,6 +5390,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subdevice    = 0xd6ee,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_CARDBUS,
        },{
+               /* AVerMedia CardBus */
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xb7e9,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_CARDBUS_501,
+       }, {
                /* TransGear 3000TV */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
@@ -5440,6 +5810,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subdevice    = 0x9715,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_507,
        },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xa11b,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA,
+       }, {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x1043,
@@ -5643,18 +6019,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x0000,
                .subdevice    = 0x4090,
                .driver_data  = SAA7134_BOARD_BEHOLD_409,
-       },{
-               .vendor       = PCI_VENDOR_ID_PHILIPS,
-               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-               .subvendor    = 0x0000,
-               .subdevice    = 0x5051,
-               .driver_data  = SAA7134_BOARD_BEHOLD_505FM,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
                .subvendor    = 0x0000,
                .subdevice    = 0x505B,
-               .driver_data  = SAA7134_BOARD_BEHOLD_505FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_505RDS,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
@@ -5666,13 +6036,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x0000,
                .subdevice    = 0x5071,
-               .driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_507RDS_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x0000,
                .subdevice    = 0x507B,
-               .driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_507RDS_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5696,49 +6066,49 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6070,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607FM_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6071,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607FM_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6072,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607RDS_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6073,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607RDS_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6090,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_609FM_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6091,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_609FM_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6092,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_609RDS_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6093,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_609RDS_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -5829,6 +6199,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
                .subdevice    = 0xf636,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_M103,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xf736,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_M103,
        }, {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -6114,7 +6490,6 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
        case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
-       case SAA7134_BOARD_VIDEOMATE_T750:
        case SAA7134_BOARD_MANLI_MTV001:
        case SAA7134_BOARD_MANLI_MTV002:
        case SAA7134_BOARD_BEHOLD_409FM:
@@ -6142,7 +6517,10 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_407FM:
        case SAA7134_BOARD_BEHOLD_409:
        case SAA7134_BOARD_BEHOLD_505FM:
+       case SAA7134_BOARD_BEHOLD_505RDS:
        case SAA7134_BOARD_BEHOLD_507_9FM:
+       case SAA7134_BOARD_BEHOLD_507RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_507RDS_MK5:
        case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
        case SAA7134_BOARD_REAL_ANGEL_220:
        case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
@@ -6196,6 +6574,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
                msleep(10);
                break;
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+               /* power-down tuner chip */
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x08400000, 0x08400000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0);
+               msleep(10);
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x08400000, 0x08400000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0x08400000);
+               msleep(10);
+               dev->has_remote = SAA7134_REMOTE_I2C;
+               break;
        case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
                saa7134_set_gpio(dev, 23, 0);
                msleep(10);
@@ -6253,7 +6641,14 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
        case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-       case SAA7134_BOARD_BEHOLD_607_9FM:
+       case SAA7134_BOARD_BEHOLD_607FM_MK3:
+       case SAA7134_BOARD_BEHOLD_607FM_MK5:
+       case SAA7134_BOARD_BEHOLD_609FM_MK3:
+       case SAA7134_BOARD_BEHOLD_609FM_MK5:
+       case SAA7134_BOARD_BEHOLD_607RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_607RDS_MK5:
+       case SAA7134_BOARD_BEHOLD_609RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_609RDS_MK5:
        case SAA7134_BOARD_BEHOLD_M6:
        case SAA7134_BOARD_BEHOLD_M63:
        case SAA7134_BOARD_BEHOLD_M6_EXTRA:
@@ -6635,6 +7030,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
 
        switch (dev->board) {
        case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
        {
                struct v4l2_priv_tun_config tea5767_cfg;
                struct tea5767_ctrl ctl;
index 2def6fec814bb31adaf6e2e32d476b13bdeb6107..94a023a14bbc7109843cd7ebae941204d9659604 100644 (file)
@@ -331,6 +331,10 @@ void saa7134_buffer_next(struct saa7134_dev *dev,
                dprintk("buffer_next %p\n",NULL);
                saa7134_set_dmabits(dev);
                del_timer(&q->timeout);
+
+               if (card_has_mpeg(dev))
+                       if (dev->ts_started)
+                               saa7134_ts_stop(dev);
        }
 }
 
@@ -416,6 +420,19 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
                ctrl |= SAA7134_MAIN_CTRL_TE5;
                irq  |= SAA7134_IRQ1_INTE_RA2_1 |
                        SAA7134_IRQ1_INTE_RA2_0;
+
+               /* dma: setup channel 5 (= TS) */
+
+               saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
+               saa_writeb(SAA7134_TS_DMA1,
+                       ((dev->ts.nr_packets - 1) >> 8) & 0xff);
+               /* TSNOPIT=0, TSCOLAP=0 */
+               saa_writeb(SAA7134_TS_DMA2,
+                       (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
+               saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
+               saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
+                                                 SAA7134_RS_CONTROL_ME |
+                                                 (dev->ts.pt_ts.dma >> 12));
        }
 
        /* set task conditions + field handling */
@@ -775,7 +792,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       vfd->minor   = -1;
        vfd->v4l2_dev  = &dev->v4l2_dev;
        vfd->release = video_device_release;
        vfd->debug   = video_debug;
index 4eff1ca8593cd9398fd15ce06d2e0c02ddf71d09..31930f26ffc7d5963aab8d24c7b3a70c918a62e3 100644 (file)
@@ -48,6 +48,7 @@
 #include "isl6405.h"
 #include "lnbp21.h"
 #include "tuner-simple.h"
+#include "tda10048.h"
 #include "tda18271.h"
 #include "lgdt3305.h"
 #include "tda8290.h"
@@ -978,6 +979,18 @@ static struct lgdt3305_config hcw_lgdt3305_config = {
        .vsb_if_khz         = 3250,
 };
 
+static struct tda10048_config hcw_tda10048_config = {
+       .demod_address    = 0x10 >> 1,
+       .output_mode      = TDA10048_SERIAL_OUTPUT,
+       .fwbulkwritelen   = TDA10048_BULKWRITE_200,
+       .inversion        = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_3300,
+       .dtv7_if_freq_khz = TDA10048_IF_3500,
+       .dtv8_if_freq_khz = TDA10048_IF_4000,
+       .clk_freq_khz     = TDA10048_CLK_16000,
+       .disable_gate_access = 1,
+};
+
 static struct tda18271_std_map hauppauge_tda18271_std_map = {
        .atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 4,
                      .if_lvl = 1, .rfagc_top = 0x58, },
@@ -1106,6 +1119,19 @@ static int dvb_init(struct saa7134_dev *dev)
                                         &tda827x_cfg_2) < 0)
                        goto dettach_frontend;
                break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+               fe0->dvb.frontend = dvb_attach(tda10048_attach,
+                                              &hcw_tda10048_config,
+                                              &dev->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda829x_attach, fe0->dvb.frontend,
+                                  &dev->i2c_adap, 0x4b,
+                                  &tda829x_no_probe);
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                                  0x60, &dev->i2c_adap,
+                                  &hcw_tda18271_config);
+               }
+               break;
        case SAA7134_BOARD_PHILIPS_TIGER:
                if (configure_tda827x_fe(dev, &philips_tiger_config,
                                         &tda827x_cfg_0) < 0)
index 9db3472667e52d311f1aab49bd003efb21cac30a..add1757f89303851afa45f49d5c6975641efde9b 100644 (file)
@@ -255,6 +255,16 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
+static int empress_try_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+
+       return 0;
+}
 
 static int empress_reqbufs(struct file *file, void *priv,
                                        struct v4l2_requestbuffers *p)
@@ -450,6 +460,7 @@ static const struct v4l2_file_operations ts_fops =
 static const struct v4l2_ioctl_ops ts_ioctl_ops = {
        .vidioc_querycap                = empress_querycap,
        .vidioc_enum_fmt_vid_cap        = empress_enum_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = empress_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap           = empress_s_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap           = empress_g_fmt_vid_cap,
        .vidioc_reqbufs                 = empress_reqbufs,
@@ -491,11 +502,8 @@ static void empress_signal_update(struct work_struct *work)
 
        if (dev->nosignal) {
                dprintk("no video signal\n");
-               ts_reset_encoder(dev);
        } else {
                dprintk("video signal acquired\n");
-               if (atomic_read(&dev->empress_users))
-                       ts_init_encoder(dev);
        }
 }
 
index f3e285aa2fb4ee66ea8a8e8365f0995816b9fd53..8096dace5f6c77d9b2eafde934300aea74a05f50 100644 (file)
@@ -259,7 +259,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
                                /* workaround for a saa7134 i2c bug
                                 * needed to talk to the mt352 demux
                                 * thanks to pinnacle for the hint */
-                               int quirk = 0xfd;
+                               int quirk = 0xfe;
                                d1printk(" [%02x quirk]",quirk);
                                i2c_send_byte(dev,START,quirk);
                                i2c_recv_byte(dev);
@@ -321,33 +321,6 @@ static u32 functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL;
 }
 
-static int attach_inform(struct i2c_client *client)
-{
-       struct saa7134_dev *dev = client->adapter->algo_data;
-
-       d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
-               client->driver->driver.name, client->addr, client->name);
-
-       /* Am I an i2c remote control? */
-
-       switch (client->addr) {
-               case 0x7a:
-               case 0x47:
-               case 0x71:
-               case 0x2d:
-               case 0x30:
-               {
-                       struct IR_i2c *ir = i2c_get_clientdata(client);
-                       d1printk("%s i2c IR detected (%s).\n",
-                                client->driver->driver.name, ir->phys);
-                       saa7134_set_i2c_ir(dev,ir);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
 static struct i2c_algorithm saa7134_algo = {
        .master_xfer   = saa7134_i2c_xfer,
        .functionality = functionality,
@@ -358,7 +331,6 @@ static struct i2c_adapter saa7134_adap_template = {
        .name          = "saa7134",
        .id            = I2C_HW_SAA7134,
        .algo          = &saa7134_algo,
-       .client_register = attach_inform,
 };
 
 static struct i2c_client saa7134_client_template = {
@@ -433,6 +405,9 @@ int saa7134_i2c_register(struct saa7134_dev *dev)
        saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata));
        if (i2c_scan)
                do_i2c_scan(dev->name,&dev->i2c_client);
+
+       /* Instantiate the IR receiver device, if present */
+       saa7134_probe_i2c_ir(dev);
        return 0;
 }
 
index 8a106d36e7232c4bce0c38aef1071526cdf93ae1..6e219c2db8419013ab3ced30470ad1c19431974a 100644 (file)
@@ -60,7 +60,7 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
 #define dprintk(fmt, arg...)   if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
-       printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+       printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg)
 
 /* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
 static int saa7134_rc5_irq(struct saa7134_dev *dev);
@@ -134,10 +134,10 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
        int gpio;
 
        /* <dev> is needed to access GPIO. Used by the saa_readl macro. */
-       struct saa7134_dev *dev = ir->c.adapter->algo_data;
+       struct saa7134_dev *dev = ir->c->adapter->algo_data;
        if (dev == NULL) {
                dprintk("get_key_msi_tvanywhere_plus: "
-                       "gir->c.adapter->algo_data is NULL!\n");
+                       "gir->c->adapter->algo_data is NULL!\n");
                return -EIO;
        }
 
@@ -156,7 +156,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
 
        /* GPIO says there is a button press. Get it. */
 
-       if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -179,7 +179,7 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -202,7 +202,7 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char buf[5], cod4, code3, code4;
 
        /* poll IR chip */
-       if (5 != i2c_master_recv(&ir->c,buf,5))
+       if (5 != i2c_master_recv(ir->c, buf, 5))
                return -EIO;
 
        cod4    = buf[4];
@@ -224,7 +224,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char data[12];
        u32 gpio;
 
-       struct saa7134_dev *dev = ir->c.adapter->algo_data;
+       struct saa7134_dev *dev = ir->c->adapter->algo_data;
 
        /* rising SAA7134_GPIO_GPRESCAN reads the status */
        saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
@@ -235,9 +235,9 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        if (0x400000 & ~gpio)
                return 0; /* No button press */
 
-       ir->c.addr = 0x5a >> 1;
+       ir->c->addr = 0x5a >> 1;
 
-       if (12 != i2c_master_recv(&ir->c, data, 12)) {
+       if (12 != i2c_master_recv(ir->c, data, 12)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -267,7 +267,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
        unsigned int start = 0,parity = 0,code = 0;
 
        /* poll IR chip */
-       if (4 != i2c_master_recv(&ir->c, b, 4)) {
+       if (4 != i2c_master_recv(ir->c, b, 4)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -447,6 +447,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
        case SAA7134_BOARD_AVERMEDIA_M102:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
@@ -506,7 +507,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_407FM:
        case SAA7134_BOARD_BEHOLD_409:
        case SAA7134_BOARD_BEHOLD_505FM:
+       case SAA7134_BOARD_BEHOLD_505RDS:
        case SAA7134_BOARD_BEHOLD_507_9FM:
+       case SAA7134_BOARD_BEHOLD_507RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_507RDS_MK5:
                ir_codes     = ir_codes_manli;
                mask_keycode = 0x003f00;
                mask_keyup   = 0x004000;
@@ -678,55 +682,101 @@ void saa7134_input_fini(struct saa7134_dev *dev)
        dev->remote = NULL;
 }
 
-void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
 {
+       struct i2c_board_info info;
+       struct IR_i2c_init_data init_data;
+       const unsigned short addr_list[] = {
+               0x7a, 0x47, 0x71, 0x2d,
+               I2C_CLIENT_END
+       };
+
+       struct i2c_msg msg_msi = {
+               .addr = 0x50,
+               .flags = I2C_M_RD,
+               .len = 0,
+               .buf = NULL,
+       };
+
+       int rc;
+
        if (disable_ir) {
-               dprintk("Found supported i2c remote, but IR has been disabled\n");
-               ir->get_key=NULL;
+               dprintk("IR has been disabled, not probing for i2c remote\n");
                return;
        }
 
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
        switch (dev->board) {
        case SAA7134_BOARD_PINNACLE_PCTV_110i:
        case SAA7134_BOARD_PINNACLE_PCTV_310i:
-               snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
+               init_data.name = "Pinnacle PCTV";
                if (pinnacle_remote == 0) {
-                       ir->get_key   = get_key_pinnacle_color;
-                       ir->ir_codes = ir_codes_pinnacle_color;
+                       init_data.get_key = get_key_pinnacle_color;
+                       init_data.ir_codes = ir_codes_pinnacle_color;
                } else {
-                       ir->get_key   = get_key_pinnacle_grey;
-                       ir->ir_codes = ir_codes_pinnacle_grey;
+                       init_data.get_key = get_key_pinnacle_grey;
+                       init_data.ir_codes = ir_codes_pinnacle_grey;
                }
                break;
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
-               snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
-               ir->get_key   = get_key_purpletv;
-               ir->ir_codes  = ir_codes_purpletv;
+               init_data.name = "Purple TV";
+               init_data.get_key = get_key_purpletv;
+               init_data.ir_codes = ir_codes_purpletv;
                break;
        case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
-               snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus");
-               ir->get_key  = get_key_msi_tvanywhere_plus;
-               ir->ir_codes = ir_codes_msi_tvanywhere_plus;
+               init_data.name = "MSI TV@nywhere Plus";
+               init_data.get_key = get_key_msi_tvanywhere_plus;
+               init_data.ir_codes = ir_codes_msi_tvanywhere_plus;
+               info.addr = 0x30;
+               /* MSI TV@nywhere Plus controller doesn't seem to
+                  respond to probes unless we read something from
+                  an existing device. Weird...
+                  REVISIT: might no longer be needed */
+               rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+               dprintk(KERN_DEBUG "probe 0x%02x @ %s: %s\n",
+                       msg_msi.addr, dev->i2c_adap.name,
+                       (1 == rc) ? "yes" : "no");
                break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-               snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110");
-               ir->get_key   = get_key_hvr1110;
-               ir->ir_codes  = ir_codes_hauppauge_new;
-               break;
-       case SAA7134_BOARD_BEHOLD_607_9FM:
+               init_data.name = "HVR 1110";
+               init_data.get_key = get_key_hvr1110;
+               init_data.ir_codes = ir_codes_hauppauge_new;
+               break;
+       case SAA7134_BOARD_BEHOLD_607FM_MK3:
+       case SAA7134_BOARD_BEHOLD_607FM_MK5:
+       case SAA7134_BOARD_BEHOLD_609FM_MK3:
+       case SAA7134_BOARD_BEHOLD_609FM_MK5:
+       case SAA7134_BOARD_BEHOLD_607RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_607RDS_MK5:
+       case SAA7134_BOARD_BEHOLD_609RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_609RDS_MK5:
        case SAA7134_BOARD_BEHOLD_M6:
        case SAA7134_BOARD_BEHOLD_M63:
        case SAA7134_BOARD_BEHOLD_M6_EXTRA:
        case SAA7134_BOARD_BEHOLD_H6:
-               snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
-               ir->get_key   = get_key_beholdm6xx;
-               ir->ir_codes  = ir_codes_behold;
+               init_data.name = "BeholdTV";
+               init_data.get_key = get_key_beholdm6xx;
+               init_data.ir_codes = ir_codes_behold;
                break;
-       default:
-               dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+               info.addr = 0x40;
                break;
        }
 
+       if (init_data.name)
+               info.platform_data = &init_data;
+       /* No need to probe if address is known */
+       if (info.addr) {
+               i2c_new_device(&dev->i2c_adap, &info);
+               return;
+       }
+
+       /* Address not known, fallback to probing */
+       i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
 }
 
 static int saa7134_rc5_irq(struct saa7134_dev *dev)
index cc8b923afbc077c37cee7708a4518c2b91968f09..3fa652279ac091bcbc464766ea42da38982bae2e 100644 (file)
@@ -65,35 +65,10 @@ static int buffer_activate(struct saa7134_dev *dev,
        /* start DMA */
        saa7134_set_dmabits(dev);
 
-       mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT);
-
-       if (dev->ts_state == SAA7134_TS_BUFF_DONE) {
-               /* Clear TS cache */
-               dev->buff_cnt = 0;
-               saa_writeb(SAA7134_TS_SERIAL1, 0x00);
-               saa_writeb(SAA7134_TS_SERIAL1, 0x03);
-               saa_writeb(SAA7134_TS_SERIAL1, 0x00);
-               saa_writeb(SAA7134_TS_SERIAL1, 0x01);
-
-               /* TS clock non-inverted */
-               saa_writeb(SAA7134_TS_SERIAL1, 0x00);
-
-               /* Start TS stream */
-               switch (saa7134_boards[dev->board].ts_type) {
-               case SAA7134_MPEG_TS_PARALLEL:
-                       saa_writeb(SAA7134_TS_SERIAL0, 0x40);
-                       saa_writeb(SAA7134_TS_PARALLEL, 0xec);
-                       break;
-               case SAA7134_MPEG_TS_SERIAL:
-                       saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
-                       saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
-                       saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
-                       saa_writeb(SAA7134_TS_SERIAL1, 0x02);
-                       break;
-               }
+       mod_timer(&dev->ts_q.timeout, jiffies+TS_BUFFER_TIMEOUT);
 
-               dev->ts_state = SAA7134_TS_STARTED;
-       }
+       if (!dev->ts_started)
+               saa7134_ts_start(dev);
 
        return 0;
 }
@@ -104,7 +79,6 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        struct saa7134_dev *dev = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
        unsigned int lines, llength, size;
-       u32 control;
        int err;
 
        dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
@@ -121,8 +95,11 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        }
 
        if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+
                struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
+               dprintk("buffer_prepare: needs_init\n");
+
                buf->vb.width  = llength;
                buf->vb.height = lines;
                buf->vb.size   = size;
@@ -139,23 +116,6 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                        goto oops;
        }
 
-       dev->buff_cnt++;
-
-       if (dev->buff_cnt == dev->ts.nr_bufs) {
-               dev->ts_state = SAA7134_TS_BUFF_DONE;
-               /* dma: setup channel 5 (= TS) */
-               control = SAA7134_RS_CONTROL_BURST_16 |
-                       SAA7134_RS_CONTROL_ME |
-                       (buf->pt->dma >> 12);
-
-               saa_writeb(SAA7134_TS_DMA0, (lines - 1) & 0xff);
-               saa_writeb(SAA7134_TS_DMA1, ((lines - 1) >> 8) & 0xff);
-               /* TSNOPIT=0, TSCOLAP=0 */
-               saa_writeb(SAA7134_TS_DMA2, (((lines - 1) >> 16) & 0x3f) | 0x00);
-               saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
-               saa_writel(SAA7134_RS_CONTROL(5), control);
-       }
-
        buf->vb.state = VIDEOBUF_PREPARED;
        buf->activate = buffer_activate;
        buf->vb.field = field;
@@ -175,8 +135,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
        if (0 == *count)
                *count = dev->ts.nr_bufs;
        *count = saa7134_buffer_count(*size,*count);
-       dev->buff_cnt = 0;
-       dev->ts_state = SAA7134_TS_STOPPED;
+
        return 0;
 }
 
@@ -193,11 +152,9 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
        struct saa7134_dev *dev = q->priv_data;
 
-       if (dev->ts_state == SAA7134_TS_STARTED) {
-               /* Stop TS transport */
-               saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
-               dev->ts_state = SAA7134_TS_STOPPED;
-       }
+       if (dev->ts_started)
+               saa7134_ts_stop(dev);
+
        saa7134_dma_free(q,buf);
 }
 
@@ -214,7 +171,7 @@ EXPORT_SYMBOL_GPL(saa7134_ts_qops);
 
 static unsigned int tsbufs = 8;
 module_param(tsbufs, int, 0444);
-MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32");
+MODULE_PARM_DESC(tsbufs, "number of ts buffers for read/write IO, range 2-32");
 
 static unsigned int ts_nr_packets = 64;
 module_param(ts_nr_packets, int, 0444);
@@ -256,6 +213,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
        dev->ts_q.timeout.data     = (unsigned long)(&dev->ts_q);
        dev->ts_q.dev              = dev;
        dev->ts_q.need_two         = 1;
+       dev->ts_started            = 0;
        saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);
 
        /* init TS hw */
@@ -264,13 +222,67 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
        return 0;
 }
 
+/* Function for stop TS */
+int saa7134_ts_stop(struct saa7134_dev *dev)
+{
+       dprintk("TS stop\n");
+
+       BUG_ON(!dev->ts_started);
+
+       /* Stop TS stream */
+       switch (saa7134_boards[dev->board].ts_type) {
+       case SAA7134_MPEG_TS_PARALLEL:
+               saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+               dev->ts_started = 0;
+               break;
+       case SAA7134_MPEG_TS_SERIAL:
+               saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+               dev->ts_started = 0;
+               break;
+       }
+       return 0;
+}
+
+/* Function for start TS */
+int saa7134_ts_start(struct saa7134_dev *dev)
+{
+       dprintk("TS start\n");
+
+       BUG_ON(dev->ts_started);
+
+       saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+       saa_writeb(SAA7134_TS_SERIAL1, 0x03);
+       saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+       saa_writeb(SAA7134_TS_SERIAL1, 0x01);
+
+       /* TS clock non-inverted */
+       saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+
+       /* Start TS stream */
+       switch (saa7134_boards[dev->board].ts_type) {
+       case SAA7134_MPEG_TS_PARALLEL:
+               saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+               saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+               break;
+       case SAA7134_MPEG_TS_SERIAL:
+               saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
+               saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+               saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
+               saa_writeb(SAA7134_TS_SERIAL1, 0x02);
+               break;
+       }
+
+       dev->ts_started = 1;
+
+       return 0;
+}
+
 int saa7134_ts_fini(struct saa7134_dev *dev)
 {
        saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts);
        return 0;
 }
 
-
 void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
 {
        enum v4l2_field field;
index 493cad941460e0fc32725332d907e19959c474e6..e305c1674cee2415432519b2b6caf28062411cd0 100644 (file)
@@ -1057,6 +1057,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                buf->vb.field  = field;
                buf->fmt       = fh->fmt;
                buf->pt        = &fh->pt_cap;
+               dev->video_q.curr = NULL;
 
                err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
                if (err)
@@ -1423,11 +1424,13 @@ video_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct saa7134_fh *fh = file->private_data;
        struct videobuf_buffer *buf = NULL;
+       unsigned int rc = 0;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
                return videobuf_poll_stream(file, &fh->vbi, wait);
 
        if (res_check(fh,RESOURCE_VIDEO)) {
+               mutex_lock(&fh->cap.vb_lock);
                if (!list_empty(&fh->cap.stream))
                        buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
        } else {
@@ -1446,13 +1449,14 @@ video_poll(struct file *file, struct poll_table_struct *wait)
        }
 
        if (!buf)
-               return POLLERR;
+               goto err;
 
        poll_wait(file, &buf->done, wait);
        if (buf->state == VIDEOBUF_DONE ||
            buf->state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
+               rc = POLLIN|POLLRDNORM;
+       mutex_unlock(&fh->cap.vb_lock);
+       return rc;
 
 err:
        mutex_unlock(&fh->cap.vb_lock);
index 0cbaf90d48745ead75f6c08149729fdf81ad39e0..82268848f26a4cc8817e17f7a6c5a4281a6952d4 100644 (file)
@@ -252,7 +252,7 @@ struct saa7134_format {
 #define SAA7134_BOARD_BEHOLD_505FM     126
 #define SAA7134_BOARD_BEHOLD_507_9FM   127
 #define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
-#define SAA7134_BOARD_BEHOLD_607_9FM   129
+#define SAA7134_BOARD_BEHOLD_607FM_MK3 129
 #define SAA7134_BOARD_BEHOLD_M6                130
 #define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131
 #define SAA7134_BOARD_GENIUS_TVGO_A11MCE   132
@@ -280,6 +280,18 @@ struct saa7134_format {
 #define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
 #define SAA7134_BOARD_HAUPPAUGE_HVR1120     155
 #define SAA7134_BOARD_HAUPPAUGE_HVR1110R3   156
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158
+#define SAA7134_BOARD_BEHOLD_505RDS         159
+#define SAA7134_BOARD_BEHOLD_507RDS_MK3     160
+#define SAA7134_BOARD_BEHOLD_507RDS_MK5     161
+#define SAA7134_BOARD_BEHOLD_607FM_MK5      162
+#define SAA7134_BOARD_BEHOLD_609FM_MK3      163
+#define SAA7134_BOARD_BEHOLD_609FM_MK5      164
+#define SAA7134_BOARD_BEHOLD_607RDS_MK3     165
+#define SAA7134_BOARD_BEHOLD_607RDS_MK5     166
+#define SAA7134_BOARD_BEHOLD_609RDS_MK3     167
+#define SAA7134_BOARD_BEHOLD_609RDS_MK5     168
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -364,6 +376,7 @@ struct saa7134_board {
 #define INTERLACE_OFF          2
 
 #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
+#define TS_BUFFER_TIMEOUT  msecs_to_jiffies(1000)  /* 1 second */
 
 struct saa7134_dev;
 struct saa7134_dma;
@@ -480,12 +493,6 @@ struct saa7134_mpeg_ops {
        void                       (*signal_change)(struct saa7134_dev *dev);
 };
 
-enum saa7134_ts_status {
-       SAA7134_TS_STOPPED,
-       SAA7134_TS_BUFF_DONE,
-       SAA7134_TS_STARTED,
-};
-
 /* global device status */
 struct saa7134_dev {
        struct list_head           devlist;
@@ -580,8 +587,7 @@ struct saa7134_dev {
        /* SAA7134_MPEG_* */
        struct saa7134_ts          ts;
        struct saa7134_dmaqueue    ts_q;
-       enum saa7134_ts_status     ts_state;
-       unsigned int               buff_cnt;
+       int                        ts_started;
        struct saa7134_mpeg_ops    *mops;
 
        /* SAA7134_MPEG_EMPRESS only */
@@ -739,6 +745,9 @@ void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
 
 int saa7134_ts_init_hw(struct saa7134_dev *dev);
 
+int saa7134_ts_start(struct saa7134_dev *dev);
+int saa7134_ts_stop(struct saa7134_dev *dev);
+
 /* ----------------------------------------------------------- */
 /* saa7134-vbi.c                                               */
 
@@ -786,7 +795,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
 int  saa7134_input_init1(struct saa7134_dev *dev);
 void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
-void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
 void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir);
 void saa7134_ir_stop(struct saa7134_dev *dev);
 
index 5990ab38a1249146a8ebdff9b2b1c8be02b58a8e..c8f05297d0f0680acccc7513231a5e561c57b3db 100644 (file)
@@ -38,7 +38,7 @@ static const char version[] = "0.24";
 static int flickerless;
 static int video_nr = -1;
 
-static struct usb_device_id device_table [] = {
+static struct usb_device_id device_table[] = {
        { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
        { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
        { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
@@ -53,7 +53,8 @@ MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
 MODULE_DESCRIPTION("SE401 USB Camera Driver");
 MODULE_LICENSE("GPL");
 module_param(flickerless, int, 0);
-MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
+MODULE_PARM_DESC(flickerless,
+               "Net frequency to adjust exposure time to (0/50/60)");
 module_param(video_nr, int, 0);
 
 static struct usb_driver se401_driver;
@@ -78,8 +79,8 @@ static void *rvmalloc(unsigned long size)
        adr = (unsigned long) mem;
        while (size > 0) {
                SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
+               adr +=  PAGE_SIZE;
+               size -=  PAGE_SIZE;
        }
 
        return mem;
@@ -95,8 +96,8 @@ static void rvfree(void *mem, unsigned long size)
        adr = (unsigned long) mem;
        while ((long) size > 0) {
                ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
+               adr +=  PAGE_SIZE;
+               size -=  PAGE_SIZE;
        }
        vfree(mem);
 }
@@ -112,7 +113,7 @@ static void rvfree(void *mem, unsigned long size)
 static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
                         unsigned short value, unsigned char *cp, int size)
 {
-       return usb_control_msg (
+       return usb_control_msg(
                se401->dev,
                set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
                req,
@@ -132,7 +133,7 @@ static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
           and the param in index, but in the logs of the windows driver they do
           this the other way around...
         */
-       return usb_control_msg (
+       return usb_control_msg(
                se401->dev,
                usb_sndctrlpipe(se401->dev, 0),
                SE401_REQ_SET_EXT_FEATURE,
@@ -152,7 +153,7 @@ static unsigned short se401_get_feature(struct usb_se401 *se401,
           wrong here to....
         */
        unsigned char cp[2];
-       usb_control_msg (
+       usb_control_msg(
                se401->dev,
                usb_rcvctrlpipe(se401->dev, 0),
                SE401_REQ_GET_EXT_FEATURE,
@@ -175,46 +176,51 @@ static unsigned short se401_get_feature(struct usb_se401 *se401,
 
 static int se401_send_pict(struct usb_se401 *se401)
 {
-       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
-       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
-       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
-       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
-       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
-       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
-       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
+       /* integration time low */
+       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);
+       /* integration time mid */
+       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);
+       /* integration time mid */
+       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);
+       /* reset level value */
+       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
+       /* red color gain */
+       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);
+       /* green color gain */
+       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);
+       /* blue color gain */
+       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);
 
        return 0;
 }
 
 static void se401_set_exposure(struct usb_se401 *se401, int brightness)
 {
-       int integration=brightness<<5;
-
-       if (flickerless==50) {
-               integration=integration-integration%106667;
-       }
-       if (flickerless==60) {
-               integration=integration-integration%88889;
-       }
-       se401->brightness=integration>>5;
-       se401->expose_h=(integration>>16)&0xff;
-       se401->expose_m=(integration>>8)&0xff;
-       se401->expose_l=integration&0xff;
+       int integration = brightness << 5;
+
+       if (flickerless == 50)
+               integration = integration-integration % 106667;
+       if (flickerless == 60)
+               integration = integration-integration % 88889;
+       se401->brightness = integration >> 5;
+       se401->expose_h = (integration >> 16) & 0xff;
+       se401->expose_m = (integration >> 8) & 0xff;
+       se401->expose_l = integration & 0xff;
 }
 
 static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
 {
-       p->brightness=se401->brightness;
-       if (se401->enhance) {
-               p->whiteness=32768;
-       } else {
-               p->whiteness=0;
-       }
-       p->colour=65535;
-       p->contrast=65535;
-       p->hue=se401->rgain<<10;
-       p->palette=se401->palette;
-       p->depth=3; /* rgb24 */
+       p->brightness = se401->brightness;
+       if (se401->enhance)
+               p->whiteness = 32768;
+       else
+               p->whiteness = 0;
+
+       p->colour = 65535;
+       p->contrast = 65535;
+       p->hue = se401->rgain << 10;
+       p->palette = se401->palette;
+       p->depth = 3; /* rgb24 */
        return 0;
 }
 
@@ -223,20 +229,19 @@ static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
 {
        if (p->palette != VIDEO_PALETTE_RGB24)
                return 1;
-       se401->palette=p->palette;
-       if (p->hue!=se401->hue) {
-               se401->rgain= p->hue>>10;
-               se401->bgain= 0x40-(p->hue>>10);
-               se401->hue=p->hue;
+       se401->palette = p->palette;
+       if (p->hue != se401->hue) {
+               se401->rgain =  p->hue >> 10;
+               se401->bgain =  0x40-(p->hue >> 10);
+               se401->hue = p->hue;
        }
-       if (p->brightness!=se401->brightness) {
+       if (p->brightness != se401->brightness)
                se401_set_exposure(se401, p->brightness);
-       }
-       if (p->whiteness>=32768) {
-               se401->enhance=1;
-       } else {
-               se401->enhance=0;
-       }
+
+       if (p->whiteness >= 32768)
+               se401->enhance = 1;
+       else
+               se401->enhance = 0;
        se401_send_pict(se401);
        se401_send_pict(se401);
        return 0;
@@ -249,7 +254,7 @@ static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
 static void se401_auto_resetlevel(struct usb_se401 *se401)
 {
        unsigned int ahrc, alrc;
-       int oldreset=se401->resetlevel;
+       int oldreset = se401->resetlevel;
 
        /* For some reason this normally read-only register doesn't get reset
           to zero after reading them just once...
@@ -258,24 +263,24 @@ static void se401_auto_resetlevel(struct usb_se401 *se401)
        se401_get_feature(se401, HV7131_REG_HIREFNOL);
        se401_get_feature(se401, HV7131_REG_LOREFNOH);
        se401_get_feature(se401, HV7131_REG_LOREFNOL);
-       ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
+       ahrc = 256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
            se401_get_feature(se401, HV7131_REG_HIREFNOL);
-       alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
+       alrc = 256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
            se401_get_feature(se401, HV7131_REG_LOREFNOL);
 
        /* Not an exact science, but it seems to work pretty well... */
        if (alrc > 10) {
-               while (alrc>=10 && se401->resetlevel < 63) {
+               while (alrc >= 10 && se401->resetlevel < 63) {
                        se401->resetlevel++;
-                       alrc /=2;
+                       alrc /= 2;
                }
        } else if (ahrc > 20) {
-               while (ahrc>=20 && se401->resetlevel > 0) {
+               while (ahrc >= 20 && se401->resetlevel > 0) {
                        se401->resetlevel--;
-                       ahrc /=2;
+                       ahrc /= 2;
                }
        }
-       if (se401->resetlevel!=oldreset)
+       if (se401->resetlevel != oldreset)
                se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
 
        return;
@@ -300,21 +305,22 @@ static void se401_button_irq(struct urb *urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+               dbg("%s - urb shutting down with status: %d",
+                                                       __func__, urb->status);
                return;
        default:
-               dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+               dbg("%s - nonzero urb status received: %d",
+                                                       __func__, urb->status);
                goto exit;
        }
 
-       if (urb->actual_length >=2) {
+       if (urb->actual_length  >= 2)
                if (se401->button)
-                       se401->buttonpressed=1;
-       }
+                       se401->buttonpressed = 1;
 exit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
+       status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status)
-               err ("%s - usb_submit_urb failed with result %d",
+               err("%s - usb_submit_urb failed with result %d",
                     __func__, status);
 }
 
@@ -336,55 +342,52 @@ static void se401_video_irq(struct urb *urb)
           keeps sending them forever...
         */
        if (length && !urb->status) {
-               se401->nullpackets=0;
-               switch(se401->scratch[se401->scratch_next].state) {
-                       case BUFFER_READY:
-                       case BUFFER_BUSY: {
-                               se401->dropped++;
-                               break;
-                       }
-                       case BUFFER_UNUSED: {
-                               memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
-                               se401->scratch[se401->scratch_next].state=BUFFER_READY;
-                               se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
-                               se401->scratch[se401->scratch_next].length=length;
-                               if (waitqueue_active(&se401->wq)) {
-                                       wake_up_interruptible(&se401->wq);
-                               }
-                               se401->scratch_overflow=0;
-                               se401->scratch_next++;
-                               if (se401->scratch_next>=SE401_NUMSCRATCH)
-                                       se401->scratch_next=0;
-                               break;
-                       }
-               }
-               se401->bayeroffset+=length;
-               if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
-                       se401->bayeroffset=0;
+               se401->nullpackets = 0;
+               switch (se401->scratch[se401->scratch_next].state) {
+               case BUFFER_READY:
+               case BUFFER_BUSY:
+                       se401->dropped++;
+                       break;
+               case BUFFER_UNUSED:
+                       memcpy(se401->scratch[se401->scratch_next].data,
+                               (unsigned char *)urb->transfer_buffer, length);
+                       se401->scratch[se401->scratch_next].state
+                                                       = BUFFER_READY;
+                       se401->scratch[se401->scratch_next].offset
+                                                       = se401->bayeroffset;
+                       se401->scratch[se401->scratch_next].length = length;
+                       if (waitqueue_active(&se401->wq))
+                               wake_up_interruptible(&se401->wq);
+                       se401->scratch_overflow = 0;
+                       se401->scratch_next++;
+                       if (se401->scratch_next >= SE401_NUMSCRATCH)
+                               se401->scratch_next = 0;
+                       break;
                }
+               se401->bayeroffset += length;
+               if (se401->bayeroffset >= se401->cheight * se401->cwidth)
+                       se401->bayeroffset = 0;
        } else {
                se401->nullpackets++;
-               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
-                       if (waitqueue_active(&se401->wq)) {
+               if (se401->nullpackets > SE401_MAX_NULLPACKETS)
+                       if (waitqueue_active(&se401->wq))
                                wake_up_interruptible(&se401->wq);
-                       }
-               }
        }
 
        /* Resubmit urb for new data */
-       urb->status=0;
-       urb->dev=se401->dev;
-       if(usb_submit_urb(urb, GFP_KERNEL))
+       urb->status = 0;
+       urb->dev = se401->dev;
+       if (usb_submit_urb(urb, GFP_KERNEL))
                dev_info(&urb->dev->dev, "urb burned down\n");
        return;
 }
 
 static void se401_send_size(struct usb_se401 *se401, int width, int height)
 {
-       int i=0;
-       int mode=0x03; /* No compression */
-       int sendheight=height;
-       int sendwidth=width;
+       int i = 0;
+       int mode = 0x03; /* No compression */
+       int sendheight = height;
+       int sendwidth = width;
 
        /* JangGu compression can only be used with the camera supported sizes,
           but bayer seems to work with any size that fits on the sensor.
@@ -392,18 +395,21 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
           4 or 16 times subcapturing, if not we use uncompressed bayer data
           but this will result in cutouts of the maximum size....
         */
-       while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
+       while (i < se401->sizes && !(se401->width[i] == width &&
+                                               se401->height[i] == height))
                i++;
-       while (i<se401->sizes) {
-               if (se401->width[i]==width*2 && se401->height[i]==height*2) {
-                       sendheight=se401->height[i];
-                       sendwidth=se401->width[i];
-                       mode=0x40;
+       while (i < se401->sizes) {
+               if (se401->width[i] == width * 2 &&
+                               se401->height[i] == height * 2) {
+                       sendheight = se401->height[i];
+                       sendwidth = se401->width[i];
+                       mode = 0x40;
                }
-               if (se401->width[i]==width*4 && se401->height[i]==height*4) {
-                       sendheight=se401->height[i];
-                       sendwidth=se401->width[i];
-                       mode=0x42;
+               if (se401->width[i] == width * 4 &&
+                               se401->height[i] == height * 4) {
+                       sendheight = se401->height[i];
+                       sendwidth = se401->width[i];
+                       mode = 0x42;
                }
                i++;
        }
@@ -412,13 +418,10 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
        se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
        se401_set_feature(se401, SE401_OPERATINGMODE, mode);
 
-       if (mode==0x03) {
-               se401->format=FMT_BAYER;
-       } else {
-               se401->format=FMT_JANGGU;
-       }
-
-       return;
+       if (mode == 0x03)
+               se401->format = FMT_BAYER;
+       else
+               se401->format = FMT_JANGGU;
 }
 
 /*
@@ -429,29 +432,31 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
 static int se401_start_stream(struct usb_se401 *se401)
 {
        struct urb *urb;
-       int err=0, i;
-       se401->streaming=1;
+       int err = 0, i;
+       se401->streaming = 1;
 
        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
 
        /* Set picture settings */
-       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
+       /* windowed + pix intg */
+       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);
        se401_send_pict(se401);
 
        se401_send_size(se401, se401->cwidth, se401->cheight);
 
-       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE,
+                                                               0, NULL, 0);
 
        /* Do some memory allocation */
-       for (i=0; i<SE401_NUMFRAMES; i++) {
-               se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
-               se401->frame[i].curpix=0;
+       for (i = 0; i < SE401_NUMFRAMES; i++) {
+               se401->frame[i].data = se401->fbuf + i * se401->maxframesize;
+               se401->frame[i].curpix = 0;
        }
-       for (i=0; i<SE401_NUMSBUF; i++) {
-               se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+       for (i = 0; i < SE401_NUMSBUF; i++) {
+               se401->sbuf[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
                if (!se401->sbuf[i].data) {
-                       for(i = i - 1; i >= 0; i--) {
+                       for (i = i - 1; i >= 0; i--) {
                                kfree(se401->sbuf[i].data);
                                se401->sbuf[i].data = NULL;
                        }
@@ -459,26 +464,26 @@ static int se401_start_stream(struct usb_se401 *se401)
                }
        }
 
-       se401->bayeroffset=0;
-       se401->scratch_next=0;
-       se401->scratch_use=0;
-       se401->scratch_overflow=0;
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
-               se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+       se401->bayeroffset = 0;
+       se401->scratch_next = 0;
+       se401->scratch_use = 0;
+       se401->scratch_overflow = 0;
+       for (i = 0; i < SE401_NUMSCRATCH; i++) {
+               se401->scratch[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
                if (!se401->scratch[i].data) {
-                       for(i = i - 1; i >= 0; i--) {
+                       for (i = i - 1; i >= 0; i--) {
                                kfree(se401->scratch[i].data);
                                se401->scratch[i].data = NULL;
                        }
                        goto nomem_sbuf;
                }
-               se401->scratch[i].state=BUFFER_UNUSED;
+               se401->scratch[i].state = BUFFER_UNUSED;
        }
 
-       for (i=0; i<SE401_NUMSBUF; i++) {
-               urb=usb_alloc_urb(0, GFP_KERNEL);
-               if(!urb) {
-                       for(i = i - 1; i >= 0; i--) {
+       for (i = 0; i < SE401_NUMSBUF; i++) {
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       for (i = i - 1; i >= 0; i--) {
                                usb_kill_urb(se401->urb[i]);
                                usb_free_urb(se401->urb[i]);
                                se401->urb[i] = NULL;
@@ -492,24 +497,24 @@ static int se401_start_stream(struct usb_se401 *se401)
                        se401_video_irq,
                        se401);
 
-               se401->urb[i]=urb;
+               se401->urb[i] = urb;
 
-               err=usb_submit_urb(se401->urb[i], GFP_KERNEL);
-               if(err)
+               err = usb_submit_urb(se401->urb[i], GFP_KERNEL);
+               if (err)
                        err("urb burned down");
        }
 
-       se401->framecount=0;
+       se401->framecount = 0;
 
        return 0;
 
  nomem_scratch:
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
+       for (i = 0; i < SE401_NUMSCRATCH; i++) {
                kfree(se401->scratch[i].data);
                se401->scratch[i].data = NULL;
        }
  nomem_sbuf:
-       for (i=0; i<SE401_NUMSBUF; i++) {
+       for (i = 0; i < SE401_NUMSBUF; i++) {
                kfree(se401->sbuf[i].data);
                se401->sbuf[i].data = NULL;
        }
@@ -523,22 +528,23 @@ static int se401_stop_stream(struct usb_se401 *se401)
        if (!se401->streaming || !se401->dev)
                return 1;
 
-       se401->streaming=0;
+       se401->streaming = 0;
 
        se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
 
        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
 
-       for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
-               usb_kill_urb(se401->urb[i]);
-               usb_free_urb(se401->urb[i]);
-               se401->urb[i]=NULL;
-               kfree(se401->sbuf[i].data);
-       }
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
+       for (i = 0; i < SE401_NUMSBUF; i++)
+               if (se401->urb[i]) {
+                       usb_kill_urb(se401->urb[i]);
+                       usb_free_urb(se401->urb[i]);
+                       se401->urb[i] = NULL;
+                       kfree(se401->sbuf[i].data);
+               }
+       for (i = 0; i < SE401_NUMSCRATCH; i++) {
                kfree(se401->scratch[i].data);
-               se401->scratch[i].data=NULL;
+               se401->scratch[i].data = NULL;
        }
 
        return 0;
@@ -546,9 +552,9 @@ static int se401_stop_stream(struct usb_se401 *se401)
 
 static int se401_set_size(struct usb_se401 *se401, int width, int height)
 {
-       int wasstreaming=se401->streaming;
+       int wasstreaming = se401->streaming;
        /* Check to see if we need to change */
-       if (se401->cwidth==width && se401->cheight==height)
+       if (se401->cwidth == width && se401->cheight == height)
                return 0;
 
        /* Check for a valid mode */
@@ -556,16 +562,16 @@ static int se401_set_size(struct usb_se401 *se401, int width, int height)
                return 1;
        if ((width & 1) || (height & 1))
                return 1;
-       if (width>se401->width[se401->sizes-1])
+       if (width > se401->width[se401->sizes-1])
                return 1;
-       if (height>se401->height[se401->sizes-1])
+       if (height > se401->height[se401->sizes-1])
                return 1;
 
        /* Stop a current stream and start it again at the new size */
        if (wasstreaming)
                se401_stop_stream(se401);
-       se401->cwidth=width;
-       se401->cheight=height;
+       se401->cwidth = width;
+       se401->cheight = height;
        if (wasstreaming)
                se401_start_stream(se401);
        return 0;
@@ -586,68 +592,68 @@ static int se401_set_size(struct usb_se401 *se401, int width, int height)
 static inline void enhance_picture(unsigned char *frame, int len)
 {
        while (len--) {
-               *frame=(((*frame^255)*(*frame^255))/255)^255;
+               *frame = (((*frame^255)*(*frame^255))/255)^255;
                frame++;
        }
 }
 
 static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
 {
-       struct se401_frame *frame=&se401->frame[se401->curframe];
-       int linelength=se401->cwidth*3;
+       struct se401_frame *frame = &se401->frame[se401->curframe];
+       int linelength = se401->cwidth * 3;
 
        if (frame->curlinepix >= linelength) {
-               frame->curlinepix=0;
-               frame->curline+=linelength;
+               frame->curlinepix = 0;
+               frame->curline += linelength;
        }
 
        /* First three are absolute, all others relative.
         * Format is rgb from right to left (mirrorred image),
         * we flip it to get bgr from left to right. */
-       if (frame->curlinepix < 3) {
-               *(frame->curline-frame->curlinepix)=1+data*4;
-       } else {
-               *(frame->curline-frame->curlinepix)=
-                   *(frame->curline-frame->curlinepix+3)+data*4;
-       }
+       if (frame->curlinepix < 3)
+               *(frame->curline-frame->curlinepix) = 1 + data * 4;
+       else
+               *(frame->curline-frame->curlinepix) =
+                   *(frame->curline-frame->curlinepix + 3) + data * 4;
        frame->curlinepix++;
 }
 
-static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
+static inline void decode_JangGu_vlc(struct usb_se401 *se401,
+                       unsigned char *data, int bit_exp, int packetlength)
 {
-       int pos=0;
-       int vlc_cod=0;
-       int vlc_size=0;
-       int vlc_data=0;
+       int pos = 0;
+       int vlc_cod = 0;
+       int vlc_size = 0;
+       int vlc_data = 0;
        int bit_cur;
        int bit;
-       data+=4;
+       data += 4;
        while (pos < packetlength) {
-               bit_cur=8;
+               bit_cur = 8;
                while (bit_cur && bit_exp) {
-                       bit=((*data)>>(bit_cur-1))&1;
+                       bit = ((*data) >> (bit_cur-1))&1;
                        if (!vlc_cod) {
                                if (bit) {
                                        vlc_size++;
                                } else {
-                                       if (!vlc_size) {
+                                       if (!vlc_size)
                                                decode_JangGu_integrate(se401, 0);
-                                       else {
-                                               vlc_cod=2;
-                                               vlc_data=0;
+                                       else {
+                                               vlc_cod = 2;
+                                               vlc_data = 0;
                                        }
                                }
                        } else {
-                               if (vlc_cod==2) {
+                               if (vlc_cod == 2) {
                                        if (!bit)
-                                               vlc_data =  -(1<<vlc_size) + 1;
+                                               vlc_data =  -(1 << vlc_size) + 1;
                                        vlc_cod--;
                                }
                                vlc_size--;
-                               vlc_data+=bit<<vlc_size;
+                               vlc_data += bit << vlc_size;
                                if (!vlc_size) {
                                        decode_JangGu_integrate(se401, vlc_data);
-                                       vlc_cod=0;
+                                       vlc_cod = 0;
                                }
                        }
                        bit_cur--;
@@ -658,186 +664,188 @@ static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *da
        }
 }
 
-static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
+static inline void decode_JangGu(struct usb_se401 *se401,
+                                               struct se401_scratch *buffer)
 {
-       unsigned char *data=buffer->data;
-       int len=buffer->length;
-       int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
-       int datapos=0;
+       unsigned char *data = buffer->data;
+       int len = buffer->length;
+       int bit_exp = 0, pix_exp = 0, frameinfo = 0, packetlength = 0, size;
+       int datapos = 0;
 
        /* New image? */
        if (!se401->frame[se401->curframe].curpix) {
-               se401->frame[se401->curframe].curlinepix=0;
-               se401->frame[se401->curframe].curline=
+               se401->frame[se401->curframe].curlinepix = 0;
+               se401->frame[se401->curframe].curline =
                    se401->frame[se401->curframe].data+
-                   se401->cwidth*3-1;
-               if (se401->frame[se401->curframe].grabstate==FRAME_READY)
-                       se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
-               se401->vlcdatapos=0;
+                   se401->cwidth * 3 - 1;
+               if (se401->frame[se401->curframe].grabstate == FRAME_READY)
+                       se401->frame[se401->curframe].grabstate = FRAME_GRABBING;
+               se401->vlcdatapos = 0;
        }
        while (datapos < len) {
-               size=1024-se401->vlcdatapos;
+               size = 1024 - se401->vlcdatapos;
                if (size+datapos > len)
-                       size=len-datapos;
+                       size = len-datapos;
                memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
-               se401->vlcdatapos+=size;
-               packetlength=0;
+               se401->vlcdatapos += size;
+               packetlength = 0;
                if (se401->vlcdatapos >= 4) {
-                       bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
-                       pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
-                       frameinfo=se401->vlcdata[0]&0xc0;
-                       packetlength=((bit_exp+47)>>4)<<1;
+                       bit_exp = se401->vlcdata[3] + (se401->vlcdata[2] << 8);
+                       pix_exp = se401->vlcdata[1] +
+                                       ((se401->vlcdata[0] & 0x3f) << 8);
+                       frameinfo = se401->vlcdata[0] & 0xc0;
+                       packetlength = ((bit_exp + 47) >> 4) << 1;
                        if (packetlength > 1024) {
-                               se401->vlcdatapos=0;
-                               datapos=len;
-                               packetlength=0;
+                               se401->vlcdatapos = 0;
+                               datapos = len;
+                               packetlength = 0;
                                se401->error++;
-                               se401->frame[se401->curframe].curpix=0;
+                               se401->frame[se401->curframe].curpix = 0;
                        }
                }
                if (packetlength && se401->vlcdatapos >= packetlength) {
-                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
-                       se401->frame[se401->curframe].curpix+=pix_exp*3;
-                       datapos+=size-(se401->vlcdatapos-packetlength);
-                       se401->vlcdatapos=0;
-                       if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
-                               if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
-                                       if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
-                                               se401->frame[se401->curframe].grabstate=FRAME_DONE;
+                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp,
+                                                               packetlength);
+                       se401->frame[se401->curframe].curpix += pix_exp * 3;
+                       datapos += size-(se401->vlcdatapos-packetlength);
+                       se401->vlcdatapos = 0;
+                       if (se401->frame[se401->curframe].curpix >= se401->cwidth * se401->cheight * 3) {
+                               if (se401->frame[se401->curframe].curpix == se401->cwidth * se401->cheight * 3) {
+                                       if (se401->frame[se401->curframe].grabstate == FRAME_GRABBING) {
+                                               se401->frame[se401->curframe].grabstate = FRAME_DONE;
                                                se401->framecount++;
                                                se401->readcount++;
                                        }
-                                       if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
-                                               se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
-                                       }
-                               } else {
+                                       if (se401->frame[(se401->curframe + 1) & (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY)
+                                               se401->curframe = (se401->curframe + 1) & (SE401_NUMFRAMES - 1);
+                               } else
                                        se401->error++;
-                               }
-                               se401->frame[se401->curframe].curpix=0;
-                               datapos=len;
+                               se401->frame[se401->curframe].curpix = 0;
+                               datapos = len;
                        }
-               } else {
-                       datapos+=size;
-               }
+               } else
+                       datapos += size;
        }
 }
 
-static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
+static inline void decode_bayer(struct usb_se401 *se401,
+                                               struct se401_scratch *buffer)
 {
-       unsigned char *data=buffer->data;
-       int len=buffer->length;
-       int offset=buffer->offset;
-       int datasize=se401->cwidth*se401->cheight;
-       struct se401_frame *frame=&se401->frame[se401->curframe];
+       unsigned char *data = buffer->data;
+       int len = buffer->length;
+       int offset = buffer->offset;
+       int datasize = se401->cwidth * se401->cheight;
+       struct se401_frame *frame = &se401->frame[se401->curframe];
+       unsigned char *framedata = frame->data, *curline, *nextline;
+       int width = se401->cwidth;
+       int blineoffset = 0, bline;
+       int linelength = width * 3, i;
 
-       unsigned char *framedata=frame->data, *curline, *nextline;
-       int width=se401->cwidth;
-       int blineoffset=0, bline;
-       int linelength=width*3, i;
 
+       if (frame->curpix == 0) {
+               if (frame->grabstate == FRAME_READY)
+                       frame->grabstate = FRAME_GRABBING;
 
-       if (frame->curpix==0) {
-               if (frame->grabstate==FRAME_READY) {
-                       frame->grabstate=FRAME_GRABBING;
-               }
-               frame->curline=framedata+linelength;
-               frame->curlinepix=0;
+               frame->curline = framedata + linelength;
+               frame->curlinepix = 0;
        }
 
-       if (offset!=frame->curpix) {
+       if (offset != frame->curpix) {
                /* Regard frame as lost :( */
-               frame->curpix=0;
+               frame->curpix = 0;
                se401->error++;
                return;
        }
 
        /* Check if we have to much data */
-       if (frame->curpix+len > datasize) {
-               len=datasize-frame->curpix;
-       }
-       if (se401->cheight%4)
-               blineoffset=1;
-       bline=frame->curpix/se401->cwidth+blineoffset;
-
-       curline=frame->curline;
-       nextline=curline+linelength;
-       if (nextline >= framedata+datasize*3)
-               nextline=curline;
+       if (frame->curpix + len > datasize)
+               len = datasize-frame->curpix;
+
+       if (se401->cheight % 4)
+               blineoffset = 1;
+       bline = frame->curpix / se401->cwidth+blineoffset;
+
+       curline = frame->curline;
+       nextline = curline + linelength;
+       if (nextline >= framedata+datasize * 3)
+               nextline = curline;
        while (len) {
-               if (frame->curlinepix>=width) {
-                       frame->curlinepix-=width;
-                       bline=frame->curpix/width+blineoffset;
-                       curline+=linelength*2;
-                       nextline+=linelength*2;
-                       if (curline >= framedata+datasize*3) {
+               if (frame->curlinepix >= width) {
+                       frame->curlinepix -= width;
+                       bline = frame->curpix / width + blineoffset;
+                       curline += linelength*2;
+                       nextline += linelength*2;
+                       if (curline >= framedata+datasize * 3) {
                                frame->curlinepix++;
-                               curline-=3;
-                               nextline-=3;
+                               curline -= 3;
+                               nextline -= 3;
                                len--;
                                data++;
                                frame->curpix++;
                        }
                        if (nextline >= framedata+datasize*3)
-                               nextline=curline;
+                               nextline = curline;
                }
-               if ((bline&1)) {
-                       if ((frame->curlinepix&1)) {
-                               *(curline+2)=*data;
-                               *(curline-1)=*data;
-                               *(nextline+2)=*data;
-                               *(nextline-1)=*data;
+               if (bline & 1) {
+                       if (frame->curlinepix & 1) {
+                               *(curline + 2) = *data;
+                               *(curline - 1) = *data;
+                               *(nextline + 2) = *data;
+                               *(nextline - 1) = *data;
                        } else {
-                               *(curline+1)=
-                                       (*(curline+1)+*data)/2;
-                               *(curline-2)=
-                                       (*(curline-2)+*data)/2;
-                               *(nextline+1)=*data;
-                               *(nextline-2)=*data;
+                               *(curline + 1) =
+                                       (*(curline + 1) + *data) / 2;
+                               *(curline-2) =
+                                       (*(curline - 2) + *data) / 2;
+                               *(nextline + 1) = *data;
+                               *(nextline - 2) = *data;
                        }
                } else {
-                       if ((frame->curlinepix&1)) {
-                               *(curline+1)=
-                                       (*(curline+1)+*data)/2;
-                               *(curline-2)=
-                                       (*(curline-2)+*data)/2;
-                               *(nextline+1)=*data;
-                               *(nextline-2)=*data;
+                       if (frame->curlinepix & 1) {
+                               *(curline + 1) =
+                                       (*(curline + 1) + *data) / 2;
+                               *(curline - 2) =
+                                       (*(curline - 2) + *data) / 2;
+                               *(nextline + 1) = *data;
+                               *(nextline - 2) = *data;
                        } else {
-                               *curline=*data;
-                               *(curline-3)=*data;
-                               *nextline=*data;
-                               *(nextline-3)=*data;
+                               *curline = *data;
+                               *(curline - 3) = *data;
+                               *nextline = *data;
+                               *(nextline - 3) = *data;
                        }
                }
                frame->curlinepix++;
-               curline-=3;
-               nextline-=3;
+               curline -= 3;
+               nextline -= 3;
                len--;
                data++;
                frame->curpix++;
        }
-       frame->curline=curline;
+       frame->curline = curline;
 
-       if (frame->curpix>=datasize) {
+       if (frame->curpix >= datasize) {
                /* Fix the top line */
-               framedata+=linelength;
-               for (i=0; i<linelength; i++) {
+               framedata += linelength;
+               for (i = 0; i < linelength; i++) {
                        framedata--;
-                       *framedata=*(framedata+linelength);
+                       *framedata = *(framedata + linelength);
                }
                /* Fix the left side (green is already present) */
-               for (i=0; i<se401->cheight; i++) {
-                       *framedata=*(framedata+3);
-                       *(framedata+1)=*(framedata+4);
-                       *(framedata+2)=*(framedata+5);
-                       framedata+=linelength;
+               for (i = 0; i < se401->cheight; i++) {
+                       *framedata = *(framedata + 3);
+                       *(framedata + 1) = *(framedata + 4);
+                       *(framedata + 2) = *(framedata + 5);
+                       framedata += linelength;
                }
-               frame->curpix=0;
-               frame->grabstate=FRAME_DONE;
+               frame->curpix = 0;
+               frame->grabstate = FRAME_DONE;
                se401->framecount++;
                se401->readcount++;
-               if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
-                       se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+               if (se401->frame[(se401->curframe + 1) &
+                   (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY) {
+                       se401->curframe = (se401->curframe+1) &
+                                                       (SE401_NUMFRAMES-1);
                }
        }
 }
@@ -845,72 +853,76 @@ static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *
 static int se401_newframe(struct usb_se401 *se401, int framenr)
 {
        DECLARE_WAITQUEUE(wait, current);
-       int errors=0;
+       int errors = 0;
 
        while (se401->streaming &&
-           (se401->frame[framenr].grabstate==FRAME_READY ||
-            se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
-               if(!se401->frame[framenr].curpix) {
+           (se401->frame[framenr].grabstate == FRAME_READY ||
+            se401->frame[framenr].grabstate == FRAME_GRABBING)) {
+               if (!se401->frame[framenr].curpix)
                        errors++;
-               }
+
                wait_interruptible(
-                   se401->scratch[se401->scratch_use].state!=BUFFER_READY,
-                   &se401->wq,
-                   &wait
-               );
+                   se401->scratch[se401->scratch_use].state != BUFFER_READY,
+                                                   &se401->wq, &wait);
                if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
-                       se401->nullpackets=0;
+                       se401->nullpackets = 0;
                        dev_info(&se401->dev->dev,
-                                "too many null length packets, restarting capture\n");
+                        "too many null length packets, restarting capture\n");
                        se401_stop_stream(se401);
                        se401_start_stream(se401);
                } else {
-                       if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
-                               se401->frame[framenr].grabstate=FRAME_ERROR;
+                       if (se401->scratch[se401->scratch_use].state !=
+                                                               BUFFER_READY) {
+                               se401->frame[framenr].grabstate = FRAME_ERROR;
                                return -EIO;
                        }
-                       se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
-                       if (se401->format==FMT_JANGGU) {
-                               decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
-                       } else {
-                               decode_bayer(se401, &se401->scratch[se401->scratch_use]);
-                       }
-                       se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
+                       se401->scratch[se401->scratch_use].state = BUFFER_BUSY;
+                       if (se401->format == FMT_JANGGU)
+                               decode_JangGu(se401,
+                                       &se401->scratch[se401->scratch_use]);
+                       else
+                               decode_bayer(se401,
+                                       &se401->scratch[se401->scratch_use]);
+
+                       se401->scratch[se401->scratch_use].state =
+                                                       BUFFER_UNUSED;
                        se401->scratch_use++;
-                       if (se401->scratch_use>=SE401_NUMSCRATCH)
-                               se401->scratch_use=0;
+                       if (se401->scratch_use >= SE401_NUMSCRATCH)
+                               se401->scratch_use = 0;
                        if (errors > SE401_MAX_ERRORS) {
-                               errors=0;
+                               errors = 0;
                                dev_info(&se401->dev->dev,
-                                        "too many errors, restarting capture\n");
+                                     "too many errors, restarting capture\n");
                                se401_stop_stream(se401);
                                se401_start_stream(se401);
                        }
                }
        }
 
-       if (se401->frame[framenr].grabstate==FRAME_DONE)
+       if (se401->frame[framenr].grabstate == FRAME_DONE)
                if (se401->enhance)
-                       enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
+                       enhance_picture(se401->frame[framenr].data,
+                                       se401->cheight * se401->cwidth * 3);
        return 0;
 }
 
-static void usb_se401_remove_disconnected (struct usb_se401 *se401)
+static void usb_se401_remove_disconnected(struct usb_se401 *se401)
 {
        int i;
 
        se401->dev = NULL;
 
-       for (i=0; i<SE401_NUMSBUF; i++)
+       for (i = 0; i < SE401_NUMSBUF; i++)
                if (se401->urb[i]) {
                        usb_kill_urb(se401->urb[i]);
                        usb_free_urb(se401->urb[i]);
                        se401->urb[i] = NULL;
                        kfree(se401->sbuf[i].data);
                }
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
+
+       for (i = 0; i < SE401_NUMSCRATCH; i++)
                kfree(se401->scratch[i].data);
-       }
+
        if (se401->inturb) {
                usb_kill_urb(se401->inturb);
                usb_free_urb(se401->inturb);
@@ -965,11 +977,11 @@ static int se401_close(struct file *file)
                dev_info(&se401->dev->dev, "device unregistered\n");
                usb_se401_remove_disconnected(se401);
        } else {
-               for (i=0; i<SE401_NUMFRAMES; i++)
-                       se401->frame[i].grabstate=FRAME_UNUSED;
+               for (i = 0; i < SE401_NUMFRAMES; i++)
+                       se401->frame[i].grabstate = FRAME_UNUSED;
                if (se401->streaming)
                        se401_stop_stream(se401);
-               se401->user=0;
+               se401->user = 0;
        }
        file->private_data = NULL;
        return 0;
@@ -1065,7 +1077,7 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(vm, 0, sizeof(*vm));
                vm->size = SE401_NUMFRAMES * se401->maxframesize;
                vm->frames = SE401_NUMFRAMES;
-               for (i=0; i<SE401_NUMFRAMES; i++)
+               for (i = 0; i < SE401_NUMFRAMES; i++)
                        vm->offsets[i] = se401->maxframesize * i;
                return 0;
        }
@@ -1083,16 +1095,16 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                /* Is this according to the v4l spec??? */
                if (se401_set_size(se401, vm->width, vm->height))
                        return -EINVAL;
-               se401->frame[vm->frame].grabstate=FRAME_READY;
+               se401->frame[vm->frame].grabstate = FRAME_READY;
 
                if (!se401->streaming)
                        se401_start_stream(se401);
 
                /* Set the picture properties */
-               if (se401->framecount==0)
+               if (se401->framecount == 0)
                        se401_send_pict(se401);
                /* Calibrate the reset level after a few frames. */
-               if (se401->framecount%20==1)
+               if (se401->framecount % 20 == 1)
                        se401_auto_resetlevel(se401);
 
                return 0;
@@ -1100,13 +1112,13 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        case VIDIOCSYNC:
        {
                int *frame = arg;
-               int ret=0;
+               int ret = 0;
 
-               if(*frame <0 || *frame >= SE401_NUMFRAMES)
+               if (*frame < 0 || *frame >= SE401_NUMFRAMES)
                        return -EINVAL;
 
-               ret=se401_newframe(se401, *frame);
-               se401->frame[*frame].grabstate=FRAME_UNUSED;
+               ret = se401_newframe(se401, *frame);
+               se401->frame[*frame].grabstate = FRAME_UNUSED;
                return ret;
        }
        case VIDIOCGFBUF:
@@ -1147,36 +1159,36 @@ static long se401_ioctl(struct file *file,
 static ssize_t se401_read(struct file *file, char __user *buf,
                     size_t count, loff_t *ppos)
 {
-       int realcount=count, ret=0;
+       int realcount = count, ret = 0;
        struct video_device *dev = file->private_data;
        struct usb_se401 *se401 = (struct usb_se401 *)dev;
 
 
-       if (se401->dev == NULL)
+       if (se401->dev ==  NULL)
                return -EIO;
        if (realcount > se401->cwidth*se401->cheight*3)
-               realcount=se401->cwidth*se401->cheight*3;
+               realcount = se401->cwidth*se401->cheight*3;
 
        /* Shouldn't happen: */
-       if (se401->frame[0].grabstate==FRAME_GRABBING)
+       if (se401->frame[0].grabstate == FRAME_GRABBING)
                return -EBUSY;
-       se401->frame[0].grabstate=FRAME_READY;
-       se401->frame[1].grabstate=FRAME_UNUSED;
-       se401->curframe=0;
+       se401->frame[0].grabstate = FRAME_READY;
+       se401->frame[1].grabstate = FRAME_UNUSED;
+       se401->curframe = 0;
 
        if (!se401->streaming)
                se401_start_stream(se401);
 
        /* Set the picture properties */
-       if (se401->framecount==0)
+       if (se401->framecount == 0)
                se401_send_pict(se401);
        /* Calibrate the reset level after a few frames. */
-       if (se401->framecount%20==1)
+       if (se401->framecount%20 == 1)
                se401_auto_resetlevel(se401);
 
-       ret=se401_newframe(se401, 0);
+       ret = se401_newframe(se401, 0);
 
-       se401->frame[0].grabstate=FRAME_UNUSED;
+       se401->frame[0].grabstate = FRAME_UNUSED;
        if (ret)
                return ret;
        if (copy_to_user(buf, se401->frame[0].data, realcount))
@@ -1195,11 +1207,12 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
 
        mutex_lock(&se401->lock);
 
-       if (se401->dev == NULL) {
+       if (se401->dev ==  NULL) {
                mutex_unlock(&se401->lock);
                return -EIO;
        }
-       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1)
+                                                       & ~(PAGE_SIZE - 1))) {
                mutex_unlock(&se401->lock);
                return -EINVAL;
        }
@@ -1210,10 +1223,10 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
                        mutex_unlock(&se401->lock);
                        return -EAGAIN;
                }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
+               start +=  PAGE_SIZE;
+               pos +=  PAGE_SIZE;
                if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
+                       size -=  PAGE_SIZE;
                else
                        size = 0;
        }
@@ -1223,7 +1236,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
 }
 
 static const struct v4l2_file_operations se401_fops = {
-       .owner        THIS_MODULE,
+       .owner  =       THIS_MODULE,
        .open =         se401_open,
        .release =      se401_close,
        .read =         se401_read,
@@ -1241,71 +1254,76 @@ static struct video_device se401_template = {
 /***************************/
 static int se401_init(struct usb_se401 *se401, int button)
 {
-       int i=0, rc;
+       int i = 0, rc;
        unsigned char cp[0x40];
        char temp[200];
+       int slen;
 
        /* led on */
        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
 
        /* get camera descriptor */
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
-       if (cp[1]!=0x41) {
+       rc = se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0,
+                                                       cp, sizeof(cp));
+       if (cp[1] != 0x41) {
                err("Wrong descriptor type");
                return 1;
        }
-       sprintf (temp, "ExtraFeatures: %d", cp[3]);
+       slen = snprintf(temp, 200, "ExtraFeatures: %d", cp[3]);
 
-       se401->sizes=cp[4]+cp[5]*256;
-       se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       se401->sizes = cp[4] + cp[5] * 256;
+       se401->width = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
        if (!se401->width)
                return 1;
-       se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       se401->height = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
        if (!se401->height) {
                kfree(se401->width);
                return 1;
        }
-       for (i=0; i<se401->sizes; i++) {
-                   se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
-                   se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
+       for (i = 0; i < se401->sizes; i++) {
+               se401->width[i] = cp[6 + i * 4 + 0] + cp[6 + i*4 + 1] * 256;
+               se401->height[i] = cp[6 + i * 4 + 2] + cp[6 + i * 4 + 3] * 256;
        }
-       sprintf (temp, "%s Sizes:", temp);
-       for (i=0; i<se401->sizes; i++) {
-               sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
+       slen += snprintf(temp + slen, 200 - slen, " Sizes:");
+       for (i = 0; i < se401->sizes; i++) {
+               slen +=  snprintf(temp + slen, 200 - slen,
+                       " %dx%d", se401->width[i], se401->height[i]);
        }
        dev_info(&se401->dev->dev, "%s\n", temp);
-       se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
+       se401->maxframesize = se401->width[se401->sizes-1] *
+                                       se401->height[se401->sizes - 1] * 3;
 
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
-       se401->cwidth=cp[0]+cp[1]*256;
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
-       se401->cheight=cp[0]+cp[1]*256;
+       rc = se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
+       se401->cwidth = cp[0]+cp[1]*256;
+       rc = se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
+       se401->cheight = cp[0]+cp[1]*256;
 
        if (!(cp[2] & SE401_FORMAT_BAYER)) {
                err("Bayer format not supported!");
                return 1;
        }
        /* set output mode (BAYER) */
-       se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE,
+                                               SE401_FORMAT_BAYER, NULL, 0);
 
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
-       se401->brightness=cp[0]+cp[1]*256;
+       rc = se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
+       se401->brightness = cp[0]+cp[1]*256;
        /* some default values */
-       se401->resetlevel=0x2d;
-       se401->rgain=0x20;
-       se401->ggain=0x20;
-       se401->bgain=0x20;
+       se401->resetlevel = 0x2d;
+       se401->rgain = 0x20;
+       se401->ggain = 0x20;
+       se401->bgain = 0x20;
        se401_set_exposure(se401, 20000);
-       se401->palette=VIDEO_PALETTE_RGB24;
-       se401->enhance=1;
-       se401->dropped=0;
-       se401->error=0;
-       se401->framecount=0;
-       se401->readcount=0;
+       se401->palette = VIDEO_PALETTE_RGB24;
+       se401->enhance = 1;
+       se401->dropped = 0;
+       se401->error = 0;
+       se401->framecount = 0;
+       se401->readcount = 0;
 
        /* Start interrupt transfers for snapshot button */
        if (button) {
-               se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
+               se401->inturb = usb_alloc_urb(0, GFP_KERNEL);
                if (!se401->inturb) {
                        dev_info(&se401->dev->dev,
                                 "Allocation of inturb failed\n");
@@ -1323,7 +1341,7 @@ static int se401_init(struct usb_se401 *se401, int button)
                        return 1;
                }
        } else
-               se401->inturb=NULL;
+               se401->inturb = NULL;
 
        /* Flash the led */
        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
@@ -1340,8 +1358,8 @@ static int se401_probe(struct usb_interface *intf,
        struct usb_device *dev = interface_to_usbdev(intf);
        struct usb_interface_descriptor *interface;
        struct usb_se401 *se401;
-       char *camera_name=NULL;
-       int button=1;
+       char *camera_name = NULL;
+       int button = 1;
 
        /* We don't handle multi-config cameras */
        if (dev->descriptor.bNumConfigurations != 1)
@@ -1350,22 +1368,22 @@ static int se401_probe(struct usb_interface *intf,
        interface = &intf->cur_altsetting->desc;
 
        /* Is it an se401? */
-       if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
-               camera_name="Endpoints/Aox SE401";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
-               camera_name="Philips PCVC665K";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
-               camera_name="Kensington VideoCAM 67014";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
-               camera_name="Kensington VideoCAM 6701(5/7)";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
-               camera_name="Kensington VideoCAM 67016";
-               button=0;
+       if (le16_to_cpu(dev->descriptor.idVendor) ==  0x03e8 &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x0004) {
+               camera_name = "Endpoints/Aox SE401";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x0471 &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x030b) {
+               camera_name = "Philips PCVC665K";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x5001) {
+               camera_name = "Kensington VideoCAM 67014";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x5002) {
+               camera_name = "Kensington VideoCAM 6701(5/7)";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x5003) {
+               camera_name = "Kensington VideoCAM 67016";
+               button = 0;
        } else
                return -ENODEV;
 
@@ -1378,7 +1396,8 @@ static int se401_probe(struct usb_interface *intf,
        /* We found one */
        dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name);
 
-       if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+       se401 = kzalloc(sizeof(*se401), GFP_KERNEL);
+       if (se401 ==  NULL) {
                err("couldn't kmalloc se401 struct");
                return -ENOMEM;
        }
@@ -1396,12 +1415,14 @@ static int se401_probe(struct usb_interface *intf,
        }
 
        memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
-       memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
+       memcpy(se401->vdev.name, se401->camera_name,
+                                       strlen(se401->camera_name));
        init_waitqueue_head(&se401->wq);
        mutex_init(&se401->lock);
        wmb();
 
-       if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+       if (video_register_device(&se401->vdev,
+                                       VFL_TYPE_GRABBER, video_nr) < 0) {
                kfree(se401);
                err("video_register_device failed");
                return -EIO;
@@ -1409,20 +1430,20 @@ static int se401_probe(struct usb_interface *intf,
        dev_info(&intf->dev, "registered new video device: video%d\n",
                 se401->vdev.num);
 
-       usb_set_intfdata (intf, se401);
+       usb_set_intfdata(intf, se401);
        return 0;
 }
 
 static void se401_disconnect(struct usb_interface *intf)
 {
-       struct usb_se401 *se401 = usb_get_intfdata (intf);
+       struct usb_se401 *se401 = usb_get_intfdata(intf);
 
-       usb_set_intfdata (intf, NULL);
+       usb_set_intfdata(intf, NULL);
        if (se401) {
                video_unregister_device(&se401->vdev);
-               if (!se401->user){
+               if (!se401->user)
                        usb_se401_remove_disconnected(se401);
-               else {
+               else {
                        se401->frame[0].grabstate = FRAME_ERROR;
                        se401->frame[0].grabstate = FRAME_ERROR;
 
@@ -1435,10 +1456,10 @@ static void se401_disconnect(struct usb_interface *intf)
 }
 
 static struct usb_driver se401_driver = {
-       .name           = "se401",
-       .id_table       = device_table,
-       .probe          = se401_probe,
-       .disconnect     = se401_disconnect,
+       .name            =  "se401",
+       .id_table        =  device_table,
+       .probe           =  se401_probe,
+       .disconnect      =  se401_disconnect,
 };
 
 
@@ -1451,9 +1472,10 @@ static struct usb_driver se401_driver = {
 
 static int __init usb_se401_init(void)
 {
-       printk(KERN_INFO "SE401 usb camera driver version %s registering\n", version);
+       printk(KERN_INFO "SE401 usb camera driver version %s registering\n",
+                                                               version);
        if (flickerless)
-               if (flickerless!=50 && flickerless!=60) {
+               if (flickerless != 50 && flickerless != 60) {
                        printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n");
                        return -1;
        }
index 2ce685db5d8b2eaa91021d7668b669cf59f1e74e..bf7d2e9765b0dee82c8ecb88c68e0cf6c29ed095 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef __LINUX_se401_H
 #define __LINUX_se401_H
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 
 #ifdef se401_DEBUG
 #  define PDEBUG(level, fmt, args...) \
-if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+if (debug >= level) \
+       info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
 #else
-#  define PDEBUG(level, fmt, args...) do {} while(0)
+#  define PDEBUG(level, fmt, args...) do {} while (0)
 #endif
 
 /* An almost drop-in replacement for sleep_on_interruptible */
index b5e37a530c62a9cad5ac1401d78639c31577d62f..d369e8409ab8bfcd9bb677d189a36b0d7d8068e4 100644 (file)
@@ -81,7 +81,6 @@ struct sh_mobile_ceu_buffer {
 };
 
 struct sh_mobile_ceu_dev {
-       struct device *dev;
        struct soc_camera_host ici;
        struct soc_camera_device *icd;
 
@@ -617,7 +616,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = icd->formats[idx].depth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(ici->dev, "Providing format %s using %s\n",
                                sh_mobile_ceu_formats[k].name,
                                icd->formats[idx].name);
                }
@@ -630,7 +629,7 @@ add_single_format:
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = icd->formats[idx].depth;
                        xlate++;
-                       dev_dbg(&ici->dev,
+                       dev_dbg(ici->dev,
                                "Providing format %s in pass-through mode\n",
                                icd->formats[idx].name);
                }
@@ -657,7 +656,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -684,7 +683,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -782,7 +781,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
 
        videobuf_queue_dma_contig_init(q,
                                       &sh_mobile_ceu_videobuf_ops,
-                                      &ici->dev, &pcdev->lock,
+                                      ici->dev, &pcdev->lock,
                                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                       pcdev->is_interlaced ?
                                       V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE,
@@ -829,7 +828,6 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                goto exit;
        }
 
-       platform_set_drvdata(pdev, pcdev);
        INIT_LIST_HEAD(&pcdev->capture);
        spin_lock_init(&pcdev->lock);
 
@@ -840,7 +838,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                goto exit_kfree;
        }
 
-       base = ioremap_nocache(res->start, res->end - res->start + 1);
+       base = ioremap_nocache(res->start, resource_size(res));
        if (!base) {
                err = -ENXIO;
                dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n");
@@ -850,13 +848,12 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
        pcdev->irq = irq;
        pcdev->base = base;
        pcdev->video_limit = 0; /* only enabled if second resource exists */
-       pcdev->dev = &pdev->dev;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (res) {
                err = dma_declare_coherent_memory(&pdev->dev, res->start,
                                                  res->start,
-                                                 (res->end - res->start) + 1,
+                                                 resource_size(res),
                                                  DMA_MEMORY_MAP |
                                                  DMA_MEMORY_EXCLUSIVE);
                if (!err) {
@@ -865,7 +862,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                        goto exit_iounmap;
                }
 
-               pcdev->video_limit = (res->end - res->start) + 1;
+               pcdev->video_limit = resource_size(res);
        }
 
        /* request irq */
@@ -885,7 +882,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
        }
 
        pcdev->ici.priv = pcdev;
-       pcdev->ici.dev.parent = &pdev->dev;
+       pcdev->ici.dev = &pdev->dev;
        pcdev->ici.nr = pdev->id;
        pcdev->ici.drv_name = dev_name(&pdev->dev);
        pcdev->ici.ops = &sh_mobile_ceu_host_ops;
@@ -913,9 +910,11 @@ exit:
 
 static int sh_mobile_ceu_remove(struct platform_device *pdev)
 {
-       struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev);
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
+                                       struct sh_mobile_ceu_dev, ici);
 
-       soc_camera_host_unregister(&pcdev->ici);
+       soc_camera_host_unregister(soc_host);
        clk_put(pcdev->clk);
        free_irq(pcdev->irq, pcdev);
        if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
index 0e890cc233776d85c3cba061299761e9402e7047..16f595d4337abfb76b3c08d98bad1ced20cf0b9d 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/device.h>
-#include <linux/list.h>
 #include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/platform_device.h>
 #include <linux/vmalloc.h>
 
+#include <media/soc_camera.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
 #include <media/videobuf-core.h>
-#include <media/soc_camera.h>
 
 /* Default to VGA resolution */
 #define DEFAULT_WIDTH  640
@@ -279,7 +281,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
                return ret;
        } else if (!icd->current_fmt ||
                   icd->current_fmt->fourcc != pix->pixelformat) {
-               dev_err(&ici->dev,
+               dev_err(ici->dev,
                        "Host driver hasn't set up current format correctly!\n");
                return -EINVAL;
        }
@@ -794,7 +796,7 @@ static void scan_add_host(struct soc_camera_host *ici)
 
        list_for_each_entry(icd, &devices, list) {
                if (icd->iface == ici->nr) {
-                       icd->dev.parent = &ici->dev;
+                       icd->dev.parent = ici->dev;
                        device_register_link(icd);
                }
        }
@@ -818,7 +820,7 @@ static int scan_add_device(struct soc_camera_device *icd)
        list_for_each_entry(ici, &hosts, list) {
                if (icd->iface == ici->nr) {
                        ret = 1;
-                       icd->dev.parent = &ici->dev;
+                       icd->dev.parent = ici->dev;
                        break;
                }
        }
@@ -952,7 +954,6 @@ static void dummy_release(struct device *dev)
 
 int soc_camera_host_register(struct soc_camera_host *ici)
 {
-       int ret;
        struct soc_camera_host *ix;
 
        if (!ici || !ici->ops ||
@@ -965,12 +966,10 @@ int soc_camera_host_register(struct soc_camera_host *ici)
            !ici->ops->reqbufs ||
            !ici->ops->add ||
            !ici->ops->remove ||
-           !ici->ops->poll)
+           !ici->ops->poll ||
+           !ici->dev)
                return -EINVAL;
 
-       /* Number might be equal to the platform device ID */
-       dev_set_name(&ici->dev, "camera_host%d", ici->nr);
-
        mutex_lock(&list_lock);
        list_for_each_entry(ix, &hosts, list) {
                if (ix->nr == ici->nr) {
@@ -979,26 +978,14 @@ int soc_camera_host_register(struct soc_camera_host *ici)
                }
        }
 
+       dev_set_drvdata(ici->dev, ici);
+
        list_add_tail(&ici->list, &hosts);
        mutex_unlock(&list_lock);
 
-       ici->dev.release = dummy_release;
-
-       ret = device_register(&ici->dev);
-
-       if (ret)
-               goto edevr;
-
        scan_add_host(ici);
 
        return 0;
-
-edevr:
-       mutex_lock(&list_lock);
-       list_del(&ici->list);
-       mutex_unlock(&list_lock);
-
-       return ret;
 }
 EXPORT_SYMBOL(soc_camera_host_register);
 
@@ -1012,7 +999,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
        list_del(&ici->list);
 
        list_for_each_entry(icd, &devices, list) {
-               if (icd->dev.parent == &ici->dev) {
+               if (icd->dev.parent == ici->dev) {
                        device_unregister(&icd->dev);
                        /* Not before device_unregister(), .remove
                         * needs parent to call ici->ops->remove() */
@@ -1023,7 +1010,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
 
        mutex_unlock(&list_lock);
 
-       device_unregister(&ici->dev);
+       dev_set_drvdata(ici->dev, NULL);
 }
 EXPORT_SYMBOL(soc_camera_host_unregister);
 
@@ -1130,7 +1117,7 @@ int soc_camera_video_start(struct soc_camera_device *icd)
        vdev = video_device_alloc();
        if (!vdev)
                goto evidallocd;
-       dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
+       dev_dbg(ici->dev, "Allocated video_device %p\n", vdev);
 
        strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
 
@@ -1174,6 +1161,57 @@ void soc_camera_video_stop(struct soc_camera_device *icd)
 }
 EXPORT_SYMBOL(soc_camera_video_stop);
 
+static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
+{
+       struct soc_camera_link *icl = pdev->dev.platform_data;
+       struct i2c_adapter *adap;
+       struct i2c_client *client;
+
+       if (!icl)
+               return -EINVAL;
+
+       adap = i2c_get_adapter(icl->i2c_adapter_id);
+       if (!adap) {
+               dev_warn(&pdev->dev, "Cannot get adapter #%d. No driver?\n",
+                        icl->i2c_adapter_id);
+               /* -ENODEV and -ENXIO do not produce an error on probe()... */
+               return -ENOENT;
+       }
+
+       icl->board_info->platform_data = icl;
+       client = i2c_new_device(adap, icl->board_info);
+       if (!client) {
+               i2c_put_adapter(adap);
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, client);
+
+       return 0;
+}
+
+static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
+{
+       struct i2c_client *client = platform_get_drvdata(pdev);
+
+       if (!client)
+               return -ENODEV;
+
+       i2c_unregister_device(client);
+       i2c_put_adapter(client->adapter);
+
+       return 0;
+}
+
+static struct platform_driver __refdata soc_camera_pdrv = {
+       .probe  = soc_camera_pdrv_probe,
+       .remove = __devexit_p(soc_camera_pdrv_remove),
+       .driver = {
+               .name = "soc-camera-pdrv",
+               .owner = THIS_MODULE,
+       },
+};
+
 static int __init soc_camera_init(void)
 {
        int ret = bus_register(&soc_camera_bus_type);
@@ -1183,8 +1221,14 @@ static int __init soc_camera_init(void)
        if (ret)
                goto edrvr;
 
+       ret = platform_driver_register(&soc_camera_pdrv);
+       if (ret)
+               goto epdr;
+
        return 0;
 
+epdr:
+       driver_unregister(&ic_drv);
 edrvr:
        bus_unregister(&soc_camera_bus_type);
        return ret;
@@ -1192,6 +1236,7 @@ edrvr:
 
 static void __exit soc_camera_exit(void)
 {
+       platform_driver_unregister(&soc_camera_pdrv);
        driver_unregister(&ic_drv);
        bus_unregister(&soc_camera_bus_type);
 }
@@ -1202,3 +1247,4 @@ module_exit(soc_camera_exit);
 MODULE_DESCRIPTION("Image capture bus driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-camera-pdrv");
index 1a6d39cbd6f31b79ad91071f1d9a2802a91042a3..2e59370472788712ba3e08ae62dd2b5f2b62f2e0 100644 (file)
@@ -1137,7 +1137,7 @@ static int stk_vidioc_querybuf(struct file *filp,
        struct stk_camera *dev = priv;
        struct stk_sio_buffer *sbuf;
 
-       if (buf->index < 0 || buf->index >= dev->n_sbufs)
+       if (buf->index >= dev->n_sbufs)
                return -EINVAL;
        sbuf = dev->sio_bufs + buf->index;
        *buf = sbuf->v4lbuf;
@@ -1154,7 +1154,7 @@ static int stk_vidioc_qbuf(struct file *filp,
        if (buf->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
 
-       if (buf->index < 0 || buf->index >= dev->n_sbufs)
+       if (buf->index >= dev->n_sbufs)
                return -EINVAL;
        sbuf = dev->sio_bufs + buf->index;
        if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED)
index 005f8a46803148873f6e1dfba22a6bc36c8fcc6b..80f1cee23fa5a70bba5f3afd44faa1be21c3d3b6 100644 (file)
  * loudness - set between 0 and 15 for varying degrees of loudness effect
  *
  * maxvol   - set maximium volume to +20db (1), default is 0db(0)
- *
- *
- *  Revision: 0.7 - maxvol module parm to set maximium volume 0db or +20db
- *                             store if muted so we can return it
- *                             change balance only if flaged to
- *  Revision: 0.6 - added tone controls
- *  Revision: 0.5 - Fixed odd balance problem
- *  Revision: 0.4 - added muting
- *  Revision: 0.3 - Fixed silly reversed volume controls.  :)
- *  Revision: 0.2 - Cleaned up #defines
- *                     fixed volume control
- *          Added I2C_DRIVERID_TDA7432
- *                     added loudness insmod control
- *  Revision: 0.1 - initial version
  */
 
 #include <linux/module.h>
index d4a9ed45764b066c0b47c0c3bdd81fe52ac9734e..1585839bd0bd3d352270a6f1f2caa039a1a00bff 100644 (file)
@@ -141,7 +141,6 @@ static const struct v4l2_subdev_ops tea6415c_ops = {
        .video = &tea6415c_video_ops,
 };
 
-/* this function is called by i2c_probe */
 static int tea6415c_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
index ced6eadf347a6d2090104ef340936a3cf6cad51b..0446524d354304bb1f6ceab3dc1def63db89c98c 100644 (file)
@@ -112,7 +112,6 @@ static const struct v4l2_subdev_ops tea6420_ops = {
        .audio = &tea6420_audio_ops,
 };
 
-/* this function is called by i2c_probe */
 static int tea6420_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
diff --git a/drivers/media/video/ths7303.c b/drivers/media/video/ths7303.c
new file mode 100644 (file)
index 0000000..21781f8
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * ths7303- THS7303 Video Amplifier driver
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("TI THS7303 video amplifier driver");
+MODULE_AUTHOR("Chaithrika U S");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+/* following function is used to set ths7303 */
+static int ths7303_setvalue(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       int err = 0;
+       u8 val;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+
+       if (std & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) {
+               val = 0x02;
+               v4l2_dbg(1, debug, sd, "setting value for SDTV format\n");
+       } else {
+               val = 0x00;
+               v4l2_dbg(1, debug, sd, "disabling all channels\n");
+       }
+
+       err |= i2c_smbus_write_byte_data(client, 0x01, val);
+       err |= i2c_smbus_write_byte_data(client, 0x02, val);
+       err |= i2c_smbus_write_byte_data(client, 0x03, val);
+
+       if (err)
+               v4l2_err(sd, "write failed\n");
+
+       return err;
+}
+
+static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+       return ths7303_setvalue(sd, norm);
+}
+
+static int ths7303_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_THS7303, 0);
+}
+
+static const struct v4l2_subdev_video_ops ths7303_video_ops = {
+       .s_std_output   = ths7303_s_std_output,
+};
+
+static const struct v4l2_subdev_core_ops ths7303_core_ops = {
+       .g_chip_ident = ths7303_g_chip_ident,
+};
+
+static const struct v4l2_subdev_ops ths7303_ops = {
+       .core   = &ths7303_core_ops,
+       .video  = &ths7303_video_ops,
+};
+
+static int ths7303_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct v4l2_subdev *sd;
+       v4l2_std_id std_id = V4L2_STD_NTSC;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       if (sd == NULL)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(sd, client, &ths7303_ops);
+
+       return ths7303_setvalue(sd, std_id);
+}
+
+static int ths7303_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(sd);
+
+       return 0;
+}
+
+static const struct i2c_device_id ths7303_id[] = {
+       {"ths7303", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ths7303_id);
+
+static struct i2c_driver ths7303_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "ths7303",
+       },
+       .probe          = ths7303_probe,
+       .remove         = ths7303_remove,
+       .id_table       = ths7303_id,
+};
+
+static int __init ths7303_init(void)
+{
+       return i2c_add_driver(&ths7303_driver);
+}
+
+static void __exit ths7303_exit(void)
+{
+       i2c_del_driver(&ths7303_driver);
+}
+
+module_init(ths7303_init);
+module_exit(ths7303_exit);
+
index 78c377a399cb893d1517b4ea6f4a48a6c04d8f19..537594211a90e1ccb6fa49b74e188b642ae0c6ae 100644 (file)
@@ -309,32 +309,6 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
        }
 }
 
-static void tuner_i2c_address_check(struct tuner *t)
-{
-       if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
-           ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
-               return;
-
-       /* We already know that the XC5000 can only be located at
-        * i2c address 0x61, 0x62, 0x63 or 0x64 */
-       if ((t->type == TUNER_XC5000) &&
-           ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))
-               return;
-
-       tuner_warn("====================== WARNING! ======================\n");
-       tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
-       tuner_warn("will soon be dropped. This message indicates that your\n");
-       tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
-                  t->name, t->i2c->addr);
-       tuner_warn("To ensure continued support for your device, please\n");
-       tuner_warn("send a copy of this message, along with full dmesg\n");
-       tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
-       tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
-       tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
-                  t->i2c->adapter->name, t->i2c->addr, t->type, t->name);
-       tuner_warn("====================== WARNING! ======================\n");
-}
-
 static struct xc5000_config xc5000_cfg;
 
 static void set_type(struct i2c_client *c, unsigned int type,
@@ -438,18 +412,12 @@ static void set_type(struct i2c_client *c, unsigned int type,
                break;
        case TUNER_XC5000:
        {
-               struct dvb_tuner_ops *xc_tuner_ops;
-
                xc5000_cfg.i2c_address    = t->i2c->addr;
                /* if_khz will be set when the digital dvb_attach() occurs */
                xc5000_cfg.if_khz         = 0;
                if (!dvb_attach(xc5000_attach,
                                &t->fe, t->i2c->adapter, &xc5000_cfg))
                        goto attach_failed;
-
-               xc_tuner_ops = &t->fe.ops.tuner_ops;
-               if (xc_tuner_ops->init)
-                       xc_tuner_ops->init(&t->fe);
                break;
        }
        default:
@@ -490,7 +458,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
        tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
                  c->adapter->name, c->driver->driver.name, c->addr << 1, type,
                  t->mode_mask);
-       tuner_i2c_address_check(t);
        return;
 
 attach_failed:
index e24a38c7fa46320dac823bcb2778846db2f3e210..ac02808106c145120fbb49c72eecc85d5a54ac9c 100644 (file)
@@ -184,7 +184,7 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,                 "Silicon TDA8275C1 8290 FM"},
        { TUNER_ABSENT,                 "Thompson DTT757"},
        /* 80-89 */
-       { TUNER_PHILIPS_FM1216ME_MK3,   "Philips FQ1216LME MK3"},
+       { TUNER_PHILIPS_FQ1216LME_MK3,  "Philips FQ1216LME MK3"},
        { TUNER_LG_PAL_NEW_TAPC,        "LG TAPC G701D"},
        { TUNER_LG_NTSC_NEW_TAPC,       "LG TAPC H791F"},
        { TUNER_LG_PAL_NEW_TAPC,        "TCL 2002MB 3"},
@@ -210,7 +210,7 @@ hauppauge_tuner[] =
        { TUNER_TEA5767,                "Philips TEA5768HL FM Radio"},
        { TUNER_ABSENT,                 "Panasonic ENV57H12D5"},
        { TUNER_PHILIPS_FM1236_MK3,     "TCL MFNM05-4"},
-       { TUNER_ABSENT,                 "TCL MNM05-4"},
+       { TUNER_PHILIPS_FM1236_MK3,     "TCL MNM05-4"},
        { TUNER_PHILIPS_FM1216ME_MK3,   "TCL MPE05-2"},
        { TUNER_ABSENT,                 "TCL MQNM05-4"},
        { TUNER_ABSENT,                 "LG TAPC-W701D"},
@@ -229,7 +229,7 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,                 "Samsung THPD5222FG30A"},
        /* 120-129 */
        { TUNER_XC2028,                 "Xceive XC3028"},
-       { TUNER_ABSENT,                 "Philips FQ1216LME MK5"},
+       { TUNER_PHILIPS_FQ1216LME_MK3,  "Philips FQ1216LME MK5"},
        { TUNER_ABSENT,                 "Philips FQD1216LME"},
        { TUNER_ABSENT,                 "Conexant CX24118A"},
        { TUNER_ABSENT,                 "TCL DMF11WIP"},
index 4262e60b8116a3df1fb161ae49fa44bc0c3ae037..3750f7fadb121466918d32c46017f3f795050ba9 100644 (file)
@@ -692,7 +692,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
                        break;  /* Input detected */
        }
 
-       if ((current_std == STD_INVALID) || (try_count <= 0))
+       if ((current_std == STD_INVALID) || (try_count < 0))
                return -EINVAL;
 
        decoder->current_std = current_std;
index 900ec2129ca16a283ec351ec3efd4f1ee9827144..31d57f2d09e1ba5d39be1e6296eff2414c994e7b 100644 (file)
@@ -240,7 +240,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
        input_dev->dev.parent = &dev->dev;
 
        input_dev->evbit[0] = BIT_MASK(EV_KEY);
-       input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+       input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
 
        error = input_register_device(cam->input);
        if (error) {
@@ -263,7 +263,7 @@ static void konicawc_unregister_input(struct konicawc *cam)
 static void konicawc_report_buttonstat(struct konicawc *cam)
 {
        if (cam->input) {
-               input_report_key(cam->input, BTN_0, cam->buttonsts);
+               input_report_key(cam->input, KEY_CAMERA, cam->buttonsts);
                input_sync(cam->input);
        }
 }
index fd112f0b9d35e7082b113c37ca549c59d547c546..803d3e4e29a20316ccbe14d9c4aa0f5cb6961099 100644 (file)
@@ -103,7 +103,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
        input_dev->dev.parent = &dev->dev;
 
        input_dev->evbit[0] = BIT_MASK(EV_KEY);
-       input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+       input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
 
        error = input_register_device(cam->input);
        if (error) {
@@ -126,7 +126,7 @@ static void qcm_unregister_input(struct qcm *cam)
 static void qcm_report_buttonstat(struct qcm *cam)
 {
        if (cam->input) {
-               input_report_key(cam->input, BTN_0, cam->button_sts);
+               input_report_key(cam->input, KEY_CAMERA, cam->button_sts);
                input_sync(cam->input);
        }
 }
index 8bc03b9e1315b2a517df95392b2cd76b97b08bcd..6ba16abeebdd61af7c03e310a7e6b0b0441056b1 100644 (file)
@@ -390,10 +390,9 @@ int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
 
 void usbvision_scratch_free(struct usb_usbvision *usbvision)
 {
-       if (usbvision->scratch != NULL) {
-               vfree(usbvision->scratch);
-               usbvision->scratch = NULL;
-       }
+       vfree(usbvision->scratch);
+       usbvision->scratch = NULL;
+
 }
 
 /*
@@ -506,10 +505,9 @@ int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
  */
 void usbvision_decompress_free(struct usb_usbvision *usbvision)
 {
-       if (usbvision->IntraFrameBuffer != NULL) {
-               vfree(usbvision->IntraFrameBuffer);
-               usbvision->IntraFrameBuffer = NULL;
-       }
+       vfree(usbvision->IntraFrameBuffer);
+       usbvision->IntraFrameBuffer = NULL;
+
 }
 
 /************************************************************
index d7056a5b7f9b1bc9a463d70282cd8be47dcabc8d..90b58914f98472644e289c97ce02297490c920d2 100644 (file)
@@ -541,7 +541,7 @@ static int vidioc_enum_input (struct file *file, void *priv,
        struct usb_usbvision *usbvision = video_drvdata(file);
        int chan;
 
-       if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+       if (vi->index >= usbvision->video_inputs)
                return -EINVAL;
        if (usbvision->have_tuner) {
                chan = vi->index;
@@ -1794,7 +1794,7 @@ static struct usb_driver usbvision_driver = {
        .name           = "usbvision",
        .id_table       = usbvision_table,
        .probe          = usbvision_probe,
-       .disconnect     = usbvision_disconnect
+       .disconnect     = __devexit_p(usbvision_disconnect),
 };
 
 /*
index 0d7e38d6ff6a416ed6905b9bb66d6b3f6f2dd2f6..36a6ba92df2700710746db302c152dc61ea14842 100644 (file)
@@ -1372,21 +1372,19 @@ end:
 }
 
 /*
- * Prune an entity of its bogus controls. This currently includes processing
- * unit auto controls for which no corresponding manual control is available.
- * Such auto controls make little sense if any, and are known to crash at
- * least the SiGma Micro webcam.
+ * Prune an entity of its bogus controls using a blacklist. Bogus controls
+ * are currently the ones that crash the camera or unconditionally return an
+ * error when queried.
  */
 static void
-uvc_ctrl_prune_entity(struct uvc_entity *entity)
+uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
 {
        static const struct {
-               u8 idx_manual;
-               u8 idx_auto;
+               struct usb_device_id id;
+               u8 index;
        } blacklist[] = {
-               { 2, 11 }, /* Hue */
-               { 6, 12 }, /* White Balance Temperature */
-               { 7, 13 }, /* White Balance Component */
+               { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */
+               { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */
        };
 
        u8 *controls;
@@ -1400,19 +1398,17 @@ uvc_ctrl_prune_entity(struct uvc_entity *entity)
        size = entity->processing.bControlSize;
 
        for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
-               if (blacklist[i].idx_auto >= 8 * size ||
-                   blacklist[i].idx_manual >= 8 * size)
+               if (!usb_match_id(dev->intf, &blacklist[i].id))
                        continue;
 
-               if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
-                    uvc_test_bit(controls, blacklist[i].idx_manual))
+               if (blacklist[i].index >= 8 * size ||
+                   !uvc_test_bit(controls, blacklist[i].index))
                        continue;
 
-               uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
-                       "matching manual control, removing it.\n", entity->id,
-                       blacklist[i].idx_auto);
+               uvc_trace(UVC_TRACE_CONTROL, "%u/%u control is black listed, "
+                       "removing it.\n", entity->id, blacklist[i].index);
 
-               uvc_clear_bit(controls, blacklist[i].idx_auto);
+               uvc_clear_bit(controls, blacklist[i].index);
        }
 }
 
@@ -1442,8 +1438,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
                        bControlSize = entity->camera.bControlSize;
                }
 
-               if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
-                       uvc_ctrl_prune_entity(entity);
+               uvc_ctrl_prune_entity(dev, entity);
 
                for (i = 0; i < bControlSize; ++i)
                        ncontrols += hweight8(bmControls[i]);
index 507dc85646b2312256d7096aff7ea0e536caba3f..89927b7aec28dce2dcd9131b7e36339de826436d 100644 (file)
@@ -289,10 +289,8 @@ static int uvc_parse_format(struct uvc_device *dev,
        struct uvc_format_desc *fmtdesc;
        struct uvc_frame *frame;
        const unsigned char *start = buffer;
-       unsigned char *_buffer;
        unsigned int interval;
        unsigned int i, n;
-       int _buflen;
        __u8 ftype;
 
        format->type = buffer[2];
@@ -303,7 +301,7 @@ static int uvc_parse_format(struct uvc_device *dev,
        case VS_FORMAT_FRAME_BASED:
                n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28;
                if (buflen < n) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -338,7 +336,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        case VS_FORMAT_MJPEG:
                if (buflen < 11) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -354,7 +352,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        case VS_FORMAT_DV:
                if (buflen < 9) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -372,7 +370,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                        strlcpy(format->name, "HD-DV", sizeof format->name);
                        break;
                default:
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d: unknown DV format %u\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber, buffer[8]);
@@ -401,7 +399,7 @@ static int uvc_parse_format(struct uvc_device *dev,
        case VS_FORMAT_STREAM_BASED:
                /* Not supported yet. */
        default:
-               uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+               uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                       "interface %d unsupported format %u\n",
                       dev->udev->devnum, alts->desc.bInterfaceNumber,
                       buffer[2]);
@@ -413,20 +411,11 @@ static int uvc_parse_format(struct uvc_device *dev,
        buflen -= buffer[0];
        buffer += buffer[0];
 
-       /* Count the number of frame descriptors to test the bFrameIndex
-        * field when parsing the descriptors. We can't rely on the
-        * bNumFrameDescriptors field as some cameras don't initialize it
-        * properly.
-        */
-       for (_buflen = buflen, _buffer = buffer;
-            _buflen > 2 && _buffer[2] == ftype;
-            _buflen -= _buffer[0], _buffer += _buffer[0])
-               format->nframes++;
-
        /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
         * based formats have frame descriptors.
         */
        while (buflen > 2 && buffer[2] == ftype) {
+               frame = &format->frame[format->nframes];
                if (ftype != VS_FRAME_FRAME_BASED)
                        n = buflen > 25 ? buffer[25] : 0;
                else
@@ -435,22 +424,12 @@ static int uvc_parse_format(struct uvc_device *dev,
                n = n ? n : 3;
 
                if (buflen < 26 + 4*n) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FRAME error\n", dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
                        return -EINVAL;
                }
 
-               if (buffer[3] - 1 >= format->nframes) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
-                              "interface %d frame index %u out of range\n",
-                              dev->udev->devnum, alts->desc.bInterfaceNumber,
-                              buffer[3]);
-                       return -EINVAL;
-               }
-
-               frame = &format->frame[buffer[3] - 1];
-
                frame->bFrameIndex = buffer[3];
                frame->bmCapabilities = buffer[4];
                frame->wWidth = get_unaligned_le16(&buffer[5]);
@@ -507,6 +486,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                        10000000/frame->dwDefaultFrameInterval,
                        (100000000/frame->dwDefaultFrameInterval)%10);
 
+               format->nframes++;
                buflen -= buffer[0];
                buffer += buffer[0];
        }
@@ -518,7 +498,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
                if (buflen < 6) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d COLORFORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -664,7 +644,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        _buflen = buflen;
 
        /* Count the format and frame descriptors. */
-       while (_buflen > 2) {
+       while (_buflen > 2 && _buffer[1] == CS_INTERFACE) {
                switch (_buffer[2]) {
                case VS_FORMAT_UNCOMPRESSED:
                case VS_FORMAT_MJPEG:
@@ -729,7 +709,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        streaming->nformats = nformats;
 
        /* Parse the format descriptors. */
-       while (buflen > 2) {
+       while (buflen > 2 && buffer[1] == CS_INTERFACE) {
                switch (buffer[2]) {
                case VS_FORMAT_UNCOMPRESSED:
                case VS_FORMAT_MJPEG:
@@ -1316,7 +1296,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video,
                        continue;
 
                if (forward->extension.bNrInPins != 1) {
-                       uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
+                       uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has "
                                "more than 1 input pin.\n", entity->id);
                        return -1;
                }
@@ -1614,6 +1594,7 @@ static int uvc_probe(struct usb_interface *intf,
        INIT_LIST_HEAD(&dev->entities);
        INIT_LIST_HEAD(&dev->streaming);
        kref_init(&dev->kref);
+       atomic_set(&dev->users, 0);
 
        dev->udev = usb_get_dev(udev);
        dev->intf = usb_get_intf(intf);
@@ -1927,7 +1908,7 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
-       /* Lenovo Thinkpad SL500 */
+       /* Lenovo Thinkpad SL400/SL500 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
          .idVendor             = 0x17ef,
@@ -1936,6 +1917,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Aveo Technology USB 2.0 Camera */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x1871,
+         .idProduct            = 0x0306,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_EXTRAFIELDS },
        /* Ecamm Pico iMage */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1945,6 +1935,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_EXTRAFIELDS },
+       /* FSC WebCam V30S */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x18ec,
+         .idProduct            = 0x3288,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Bodelin ProScopeHR */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_DEV_HI
@@ -1965,8 +1964,7 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX
-                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT
-                               | UVC_QUIRK_PRUNE_CONTROLS },
+                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT },
        /* Generic USB Video Class */
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
        {}
index 0155752e4a5aea54140c55044a266df1099b8575..f854698c40618a4a5225209f1060933f1aafb430 100644 (file)
@@ -172,6 +172,20 @@ int uvc_free_buffers(struct uvc_video_queue *queue)
        return 0;
 }
 
+/*
+ * Check if buffers have been allocated.
+ */
+int uvc_queue_allocated(struct uvc_video_queue *queue)
+{
+       int allocated;
+
+       mutex_lock(&queue->mutex);
+       allocated = queue->count != 0;
+       mutex_unlock(&queue->mutex);
+
+       return allocated;
+}
+
 static void __uvc_query_buffer(struct uvc_buffer *buf,
                struct v4l2_buffer *v4l2_buf)
 {
index 21d87124986b57336afc53debe4315ce17d618a2..f152a9903862abe4780eebe67ba282f2bf6d9eac 100644 (file)
@@ -194,7 +194,7 @@ int uvc_status_init(struct uvc_device *dev)
                dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
                dev, interval);
 
-       return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+       return 0;
 }
 
 void uvc_status_cleanup(struct uvc_device *dev)
@@ -205,15 +205,30 @@ void uvc_status_cleanup(struct uvc_device *dev)
        uvc_input_cleanup(dev);
 }
 
-int uvc_status_suspend(struct uvc_device *dev)
+int uvc_status_start(struct uvc_device *dev)
+{
+       if (dev->int_urb == NULL)
+               return 0;
+
+       return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
+
+void uvc_status_stop(struct uvc_device *dev)
 {
        usb_kill_urb(dev->int_urb);
+}
+
+int uvc_status_suspend(struct uvc_device *dev)
+{
+       if (atomic_read(&dev->users))
+               usb_kill_urb(dev->int_urb);
+
        return 0;
 }
 
 int uvc_status_resume(struct uvc_device *dev)
 {
-       if (dev->int_urb == NULL)
+       if (dev->int_urb == NULL || atomic_read(&dev->users) == 0)
                return 0;
 
        return usb_submit_urb(dev->int_urb, GFP_NOIO);
index 2a80caa54fb42638d6808e8819a0fbb7c351e0aa..5e77cad29690112bb734486a62e8b766f0eebb6e 100644 (file)
@@ -46,6 +46,8 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video,
        struct uvc_menu_info *menu_info;
        struct uvc_control_mapping *mapping;
        struct uvc_control *ctrl;
+       u32 index = query_menu->index;
+       u32 id = query_menu->id;
 
        ctrl = uvc_find_control(video, query_menu->id, &mapping);
        if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
@@ -54,6 +56,10 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video,
        if (query_menu->index >= mapping->menu_count)
                return -EINVAL;
 
+       memset(query_menu, 0, sizeof(*query_menu));
+       query_menu->id = id;
+       query_menu->index = index;
+
        menu_info = &mapping->menu_info[query_menu->index];
        strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
        return 0;
@@ -245,7 +251,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
        if (fmt->type != video->streaming->type)
                return -EINVAL;
 
-       if (uvc_queue_streaming(&video->queue))
+       if (uvc_queue_allocated(&video->queue))
                return -EBUSY;
 
        ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
@@ -433,6 +439,15 @@ static int uvc_v4l2_open(struct file *file)
                goto done;
        }
 
+       if (atomic_inc_return(&video->dev->users) == 1) {
+               if ((ret = uvc_status_start(video->dev)) < 0) {
+                       usb_autopm_put_interface(video->dev->intf);
+                       atomic_dec(&video->dev->users);
+                       kfree(handle);
+                       goto done;
+               }
+       }
+
        handle->device = video;
        handle->state = UVC_HANDLE_PASSIVE;
        file->private_data = handle;
@@ -467,6 +482,9 @@ static int uvc_v4l2_release(struct file *file)
        kfree(handle);
        file->private_data = NULL;
 
+       if (atomic_dec_return(&video->dev->users) == 0)
+               uvc_status_stop(video->dev);
+
        usb_autopm_put_interface(video->dev->intf);
        kref_put(&video->dev->kref, uvc_delete);
        return 0;
@@ -512,7 +530,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(&xctrl, 0, sizeof xctrl);
                xctrl.id = ctrl->id;
 
-               uvc_ctrl_begin(video);
+              ret = uvc_ctrl_begin(video);
+              if (ret < 0)
+                       return ret;
+
                ret = uvc_ctrl_get(video, &xctrl);
                uvc_ctrl_rollback(video);
                if (ret >= 0)
@@ -529,7 +550,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                xctrl.id = ctrl->id;
                xctrl.value = ctrl->value;
 
-               uvc_ctrl_begin(video);
+              ret = uvc_ctrl_begin(video);
+              if (ret < 0)
+                       return ret;
+
                ret = uvc_ctrl_set(video, &xctrl);
                if (ret < 0) {
                        uvc_ctrl_rollback(video);
@@ -548,7 +572,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_ext_control *ctrl = ctrls->controls;
                unsigned int i;
 
-               uvc_ctrl_begin(video);
+              ret = uvc_ctrl_begin(video);
+              if (ret < 0)
+                       return ret;
+
                for (i = 0; i < ctrls->count; ++ctrl, ++i) {
                        ret = uvc_ctrl_get(video, ctrl);
                        if (ret < 0) {
@@ -648,7 +675,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        case VIDIOC_S_INPUT:
        {
-               u8 input = *(u32 *)arg + 1;
+               u32 input = *(u32 *)arg + 1;
 
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
@@ -660,7 +687,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        break;
                }
 
-               if (input > video->selector->selector.bNrInPins)
+               if (input == 0 || input > video->selector->selector.bNrInPins)
                        return -EINVAL;
 
                return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
index 6ce974d7362f2d2c442f6d7174693eb1419b9f37..01b633c734803ac3d4cf3b42a690cbedc51dc96f 100644 (file)
@@ -65,7 +65,8 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
        struct uvc_streaming_control *ctrl)
 {
        struct uvc_format *format;
-       struct uvc_frame *frame;
+       struct uvc_frame *frame = NULL;
+       unsigned int i;
 
        if (ctrl->bFormatIndex <= 0 ||
            ctrl->bFormatIndex > video->streaming->nformats)
@@ -73,11 +74,15 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
 
        format = &video->streaming->format[ctrl->bFormatIndex - 1];
 
-       if (ctrl->bFrameIndex <= 0 ||
-           ctrl->bFrameIndex > format->nframes)
-               return;
+       for (i = 0; i < format->nframes; ++i) {
+               if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
+                       frame = &format->frame[i];
+                       break;
+               }
+       }
 
-       frame = &format->frame[ctrl->bFrameIndex - 1];
+       if (frame == NULL)
+               return;
 
        if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
             (ctrl->dwMaxVideoFrameSize == 0 &&
@@ -1089,7 +1094,7 @@ int uvc_video_init(struct uvc_video_device *video)
        /* Zero bFrameIndex might be correct. Stream-based formats (including
         * MPEG-2 TS and DV) do not support frames but have a dummy frame
         * descriptor with bFrameIndex set to zero. If the default frame
-        * descriptor is not found, use the first avalable frame.
+        * descriptor is not found, use the first available frame.
         */
        for (i = format->nframes; i > 0; --i) {
                frame = &format->frame[i-1];
index e5014e668f9979307996d507d034cdc3fb793e94..3c78d3c1e4c0f7482122d7ddff4ea2c0411fea2e 100644 (file)
@@ -313,7 +313,6 @@ struct uvc_xu_control {
 #define UVC_QUIRK_BUILTIN_ISIGHT       0x00000008
 #define UVC_QUIRK_STREAM_NO_FID                0x00000010
 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
-#define UVC_QUIRK_PRUNE_CONTROLS       0x00000040
 #define UVC_QUIRK_FIX_BANDWIDTH                0x00000080
 
 /* Format flags */
@@ -634,6 +633,7 @@ struct uvc_device {
        enum uvc_device_state state;
        struct kref kref;
        struct list_head list;
+       atomic_t users;
 
        /* Video control interface */
        __u16 uvc_version;
@@ -747,6 +747,7 @@ extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
                struct uvc_buffer *buf);
 extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
                struct file *file, poll_table *wait);
+extern int uvc_queue_allocated(struct uvc_video_queue *queue);
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
        return queue->flags & UVC_QUEUE_STREAMING;
@@ -770,6 +771,8 @@ extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
 /* Status */
 extern int uvc_status_init(struct uvc_device *dev);
 extern void uvc_status_cleanup(struct uvc_device *dev);
+extern int uvc_status_start(struct uvc_device *dev);
+extern void uvc_status_stop(struct uvc_device *dev);
 extern int uvc_status_suspend(struct uvc_device *dev);
 extern int uvc_status_resume(struct uvc_device *dev);
 
index f576ef66b8078a79f42dfd9667d498a61118338f..f96475626da78949079318fe4372edf0ae7dd37e 100644 (file)
@@ -746,6 +746,7 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
                const struct v4l2_subdev_ops *ops)
 {
        v4l2_subdev_init(sd, ops);
+       sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
        /* the owner is the same as the i2c_client's driver owner */
        sd->owner = client->driver->driver.owner;
        /* i2c_client and v4l2_subdev point to one another */
@@ -897,8 +898,7 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
        };
        static const unsigned short tv_addrs[] = {
                0x42, 0x43, 0x4a, 0x4b,         /* tda8290 */
-               0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
-               0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+               0x60, 0x61, 0x62, 0x63, 0x64,
                I2C_CLIENT_END
        };
 
index 94aa485ade52efb9b87a01871366b8363a39143b..0d06e7cbd5b3187aee89bbcfb14410c69ffb013b 100644 (file)
@@ -49,6 +49,22 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
 }
 EXPORT_SYMBOL_GPL(v4l2_device_register);
 
+int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
+                                               atomic_t *instance)
+{
+       int num = atomic_inc_return(instance) - 1;
+       int len = strlen(basename);
+
+       if (basename[len - 1] >= '0' && basename[len - 1] <= '9')
+               snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
+                               "%s-%d", basename, num);
+       else
+               snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
+                               "%s%d", basename, num);
+       return num;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_set_name);
+
 void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
 {
        if (v4l2_dev->dev) {
@@ -67,8 +83,21 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
        v4l2_device_disconnect(v4l2_dev);
 
        /* Unregister subdevs */
-       list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
+       list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
                v4l2_device_unregister_subdev(sd);
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+               if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {
+                       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+                       /* We need to unregister the i2c client explicitly.
+                          We cannot rely on i2c_del_adapter to always
+                          unregister clients for us, since if the i2c bus
+                          is a platform bus, then it is never deleted. */
+                       if (client)
+                               i2c_unregister_device(client);
+               }
+#endif
+       }
 }
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 
index b7b05842cf281bda10b27572df02ff9301fb823d..f1ccf98c0a6f071d287a066a2902c4783b3675fd 100644 (file)
@@ -118,6 +118,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
                         void *priv,
                         struct videobuf_qtype_ops *int_ops)
 {
+       BUG_ON(!q);
        memset(q, 0, sizeof(*q));
        q->irqlock   = irqlock;
        q->dev       = dev;
@@ -439,6 +440,7 @@ int videobuf_reqbufs(struct videobuf_queue *q,
        }
 
        req->count = retval;
+       retval = 0;
 
  done:
        mutex_unlock(&q->vb_lock);
@@ -454,7 +456,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
                dprintk(1, "querybuf: Wrong type.\n");
                goto done;
        }
-       if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
+       if (unlikely(b->index >= VIDEO_MAX_FRAME)) {
                dprintk(1, "querybuf: index out of range.\n");
                goto done;
        }
@@ -495,7 +497,7 @@ int videobuf_qbuf(struct videobuf_queue *q,
                dprintk(1, "qbuf: Wrong type.\n");
                goto done;
        }
-       if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
+       if (b->index >= VIDEO_MAX_FRAME) {
                dprintk(1, "qbuf: index out of range.\n");
                goto done;
        }
index 0c29a019bc89b25f4f645d59cde70fc3f60703ee..d09ce83a9429af98060b7d3dd27e21923f2431ea 100644 (file)
@@ -259,19 +259,6 @@ static int __videobuf_iolock(struct videobuf_queue *q,
        return 0;
 }
 
-static int __videobuf_sync(struct videobuf_queue *q,
-                          struct videobuf_buffer *buf)
-{
-       struct videobuf_dma_contig_memory *mem = buf->priv;
-
-       BUG_ON(!mem);
-       MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
-
-       dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size,
-                               DMA_FROM_DEVICE);
-       return 0;
-}
-
 static int __videobuf_mmap_free(struct videobuf_queue *q)
 {
        unsigned int i;
@@ -433,7 +420,6 @@ static struct videobuf_qtype_ops qops = {
 
        .alloc        = __videobuf_alloc,
        .iolock       = __videobuf_iolock,
-       .sync         = __videobuf_sync,
        .mmap_free    = __videobuf_mmap_free,
        .mmap_mapper  = __videobuf_mmap_mapper,
        .video_copy_to_user = __videobuf_copy_to_user,
index da1790e57a86c87b03c530deb58435cab036b80d..a8dd22ace3fbb270b938ba815b617ba815a98fae 100644 (file)
@@ -58,9 +58,10 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
        struct page *pg;
        int i;
 
-       sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+       sglist = vmalloc(nr_pages * sizeof(*sglist));
        if (NULL == sglist)
                return NULL;
+       memset(sglist, 0, nr_pages * sizeof(*sglist));
        sg_init_table(sglist, nr_pages);
        for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
                pg = vmalloc_to_page(virt);
@@ -72,7 +73,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
        return sglist;
 
  err:
-       kfree(sglist);
+       vfree(sglist);
        return NULL;
 }
 
@@ -84,7 +85,7 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 
        if (NULL == pages[0])
                return NULL;
-       sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL);
+       sglist = vmalloc(nr_pages * sizeof(*sglist));
        if (NULL == sglist)
                return NULL;
        sg_init_table(sglist, nr_pages);
@@ -104,12 +105,12 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 
  nopage:
        dprintk(2,"sgl: oops - no page\n");
-       kfree(sglist);
+       vfree(sglist);
        return NULL;
 
  highmem:
        dprintk(2,"sgl: oops - highmem page\n");
-       kfree(sglist);
+       vfree(sglist);
        return NULL;
 }
 
@@ -230,7 +231,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
                                                (dma->vmalloc,dma->nr_pages);
        }
        if (dma->bus_addr) {
-               dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
+               dma->sglist = vmalloc(sizeof(*dma->sglist));
                if (NULL != dma->sglist) {
                        dma->sglen  = 1;
                        sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
@@ -248,10 +249,10 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
                if (0 == dma->sglen) {
                        printk(KERN_WARNING
                               "%s: videobuf_map_sg failed\n",__func__);
-                       kfree(dma->sglist);
+                       vfree(dma->sglist);
                        dma->sglist = NULL;
                        dma->sglen = 0;
-                       return -EIO;
+                       return -ENOMEM;
                }
        }
        return 0;
@@ -274,7 +275,7 @@ int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
 
        dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction);
 
-       kfree(dma->sglist);
+       vfree(dma->sglist);
        dma->sglist = NULL;
        dma->sglen = 0;
        return 0;
index 43e0998adb534bb857fdc88ada51117c914ab411..97b082fe44736423bf2a2240abc962cfdb90f999 100644 (file)
@@ -868,9 +868,9 @@ static void vino_sync_buffer(struct vino_framebuffer *fb)
        dprintk("vino_sync_buffer():\n");
 
        for (i = 0; i < fb->desc_table.page_count; i++)
-               dma_sync_single(NULL,
-                               fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
-                               PAGE_SIZE, DMA_FROM_DEVICE);
+               dma_sync_single_for_cpu(NULL,
+                                       fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+                                       PAGE_SIZE, DMA_FROM_DEVICE);
 }
 
 /* Framebuffer fifo functions (need to be locked externally) */
index ea6c577b0eb3131f7366e5b163ed317de4dad623..03dc2f3cf84af17d33530a3a6b6cc941764dbdd2 100644 (file)
@@ -1022,7 +1022,7 @@ zr36057_init (struct zoran *zr)
        zr->vbuf_bytesperline = 0;
 
        /* Avoid nonsense settings from user for default input/norm */
-       if (default_norm < 0 && default_norm > 2)
+       if (default_norm < 0 || default_norm > 2)
                default_norm = 0;
        if (default_norm == 0) {
                zr->norm = V4L2_STD_PAL;
@@ -1477,7 +1477,7 @@ static struct pci_driver zoran_driver = {
        .name = "zr36067",
        .id_table = zr36067_pci_tbl,
        .probe = zoran_probe,
-       .remove = zoran_remove,
+       .remove = __devexit_p(zoran_remove),
 };
 
 static int __init zoran_init(void)
index ac169c9eb18d04e958ff1b6bc406f5513efbf471..fc976f42f4328d70bbccb9a65a1d4bd0b5173cf5 100644 (file)
@@ -882,9 +882,11 @@ static void zr364xx_disconnect(struct usb_interface *intf)
                video_unregister_device(cam->vdev);
        cam->vdev = NULL;
        kfree(cam->buffer);
-       if (cam->framebuf)
-               vfree(cam->framebuf);
+       cam->buffer = NULL;
+       vfree(cam->framebuf);
+       cam->framebuf = NULL;
        kfree(cam);
+       cam = NULL;
 }
 
 
index c7211ab6dd4be15f61ba7cc899703f0f29b08474..39751c8cde9cb010773a43c23a926bc9001b2de7 100644 (file)
 #define SDIO_DEVICE_ID_MARVELL_8688WLAN                0x9104
 #define SDIO_DEVICE_ID_MARVELL_8688BT          0x9105
 
+#define SDIO_VENDOR_ID_SIANO                   0x039a
+#define SDIO_DEVICE_ID_SIANO_NOVA_B0           0x0201
+#define SDIO_DEVICE_ID_SIANO_NICE              0x0202
+#define SDIO_DEVICE_ID_SIANO_VEGA_A0           0x0300
+#define SDIO_DEVICE_ID_SIANO_VENICE            0x0301
+#define SDIO_DEVICE_ID_SIANO_NOVA_A0           0x1100
+#define SDIO_DEVICE_ID_SIANO_STELLAR           0x5347
+
 #endif
index ebb2ea6b499598d20c066f2d670381dedc8758c9..f24eceecc5a602562e5b3d6d1dbae338df319633 100644 (file)
@@ -347,7 +347,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
 #define V4L2_PIX_FMT_SQ905C   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
 #define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
-#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16  YVU 4:2:2     */
+#define V4L2_PIX_FMT_YVYU     v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
+#define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
 
 /*
  *     F O R M A T   E N U M E R A T I O N
diff --git a/include/media/adv7343.h b/include/media/adv7343.h
new file mode 100644 (file)
index 0000000..d6f8a4e
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * ADV7343 header file
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ADV7343_H
+#define ADV7343_H
+
+#define ADV7343_COMPOSITE_ID   (0)
+#define ADV7343_COMPONENT_ID   (1)
+#define ADV7343_SVIDEO_ID      (2)
+
+#endif                         /* End of #ifndef ADV7343_H */
index 07963d7054008be6490f79ee91a4f9740900e5d6..3ad4ed5402fb8b6782ad6b1600f8dfdfd4394ea1 100644 (file)
@@ -7,7 +7,7 @@ struct IR_i2c;
 
 struct IR_i2c {
        IR_KEYTAB_TYPE         *ir_codes;
-       struct i2c_client      c;
+       struct i2c_client      *c;
        struct input_dev       *input;
        struct ir_input_state  ir;
 
@@ -15,7 +15,15 @@ struct IR_i2c {
        unsigned char          old;
 
        struct delayed_work    work;
+       char                   name[32];
        char                   phys[32];
        int                    (*get_key)(struct IR_i2c*, u32*, u32*);
 };
+
+/* Can be passed when instantiating an ir_video i2c device */
+struct IR_i2c_init_data {
+       IR_KEYTAB_TYPE         *ir_codes;
+       const char             *name;
+       int                    (*get_key)(struct IR_i2c*, u32*, u32*);
+};
 #endif
index 37013688af44b64c8107e94fa7e416411e69dcfa..23ecead35e7a70c4f4d03fd6634ec88e8a3ae319 100644 (file)
@@ -60,7 +60,7 @@ struct soc_camera_file {
 
 struct soc_camera_host {
        struct list_head list;
-       struct device dev;
+       struct device *dev;
        unsigned char nr;                               /* Host number */
        void *priv;
        const char *drv_name;
@@ -92,11 +92,16 @@ struct soc_camera_host_ops {
 #define SOCAM_SENSOR_INVERT_VSYNC      (1 << 3)
 #define SOCAM_SENSOR_INVERT_DATA       (1 << 4)
 
+struct i2c_board_info;
+
 struct soc_camera_link {
        /* Camera bus id, used to match a camera and a bus */
        int bus_id;
        /* Per camera SOCAM_SENSOR_* bus flags */
        unsigned long flags;
+       int i2c_adapter_id;
+       struct i2c_board_info *board_info;
+       const char *module_name;
        /* Optional callbacks to power on or off and reset the sensor */
        int (*power)(struct device *, int);
        int (*reset)(struct device *);
@@ -107,6 +112,7 @@ struct soc_camera_link {
         */
        int (*set_bus_param)(struct soc_camera_link *, unsigned long flags);
        unsigned long (*query_bus_param)(struct soc_camera_link *);
+       void (*free_bus)(struct soc_camera_link *);
 };
 
 static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
@@ -116,7 +122,7 @@ static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
 
 static inline struct soc_camera_host *to_soc_camera_host(struct device *dev)
 {
-       return container_of(dev, struct soc_camera_host, dev);
+       return dev_get_drvdata(dev);
 }
 
 extern int soc_camera_host_register(struct soc_camera_host *ici);
index 7d4e2db780767709579367fe6e50cb15ee825c85..cbf97f45fbec3abd6dde9da35c074de6bc20e36f 100644 (file)
 #define TUNER_XC5000                   76      /* Xceive Silicon Tuner */
 #define TUNER_TCL_MF02GIP_5N           77      /* TCL MF02GIP_5N */
 #define TUNER_PHILIPS_FMD1216MEX_MK3   78
+#define TUNER_PHILIPS_FM1216MK5                79
+#define TUNER_PHILIPS_FQ1216LME_MK3    80      /* Active loopthrough, no FM */
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
index 1be461a2907768d29dbe060030c85dedfc4766b7..4d7e2272c42f0c37e0aabb5dbc912c6c24361a34 100644 (file)
@@ -137,6 +137,12 @@ enum {
        /* module saa7191: just ident 7191 */
        V4L2_IDENT_SAA7191 = 7191,
 
+       /* module ths7303: just ident 7303 */
+       V4L2_IDENT_THS7303 = 7303,
+
+       /* module adv7343: just ident 7343 */
+       V4L2_IDENT_ADV7343 = 7343,
+
        /* module wm8739: just ident 8739 */
        V4L2_IDENT_WM8739 = 8739,
 
index 0dd3e8e8653e136d28b97154d35c9cdb7f074b09..5d5d550e63ad0e2c7a0c1811a42e1f031743068a 100644 (file)
@@ -30,7 +30,7 @@
    basic V4L2 device-level support.
  */
 
-#define V4L2_DEVICE_NAME_SIZE (BUS_ID_SIZE + 16)
+#define V4L2_DEVICE_NAME_SIZE (20 + 16)
 
 struct v4l2_device {
        /* dev->driver_data points to this struct.
@@ -53,10 +53,31 @@ struct v4l2_device {
    dev may be NULL in rare cases (ISA devices). In that case you
    must fill in the v4l2_dev->name field before calling this function. */
 int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+
+/* Optional function to initialize the name field of struct v4l2_device using
+   the driver name and a driver-global atomic_t instance.
+   This function will increment the instance counter and returns the instance
+   value used in the name.
+
+   Example:
+
+   static atomic_t drv_instance = ATOMIC_INIT(0);
+
+   ...
+
+   instance = v4l2_device_set_name(&v4l2_dev, "foo", &drv_instance);
+
+   The first time this is called the name field will be set to foo0 and
+   this function returns 0. If the name ends with a digit (e.g. cx18),
+   then the name will be set to cx18-0 since cx180 looks really odd. */
+int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
+                                               atomic_t *instance);
+
 /* Set v4l2_dev->dev to NULL. Call when the USB parent disconnects.
    Since the parent disappears this ensures that v4l2_dev doesn't have an
    invalid parent pointer. */
 void v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
+
 /* Unregister all sub-devices and any other resources related to v4l2_dev. */
 void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
 
index 17856081c80942d6ec9f4e0e7a0d362d2c4277df..a503e1cee78bd7e2554faf22310ff78db54c5a57 100644 (file)
@@ -230,12 +230,16 @@ struct v4l2_subdev_ops {
 
 #define V4L2_SUBDEV_NAME_SIZE 32
 
+/* Set this flag if this subdev is a i2c device. */
+#define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
+
 /* Each instance of a subdev driver should create this struct, either
    stand-alone or embedded in a larger struct.
  */
 struct v4l2_subdev {
        struct list_head list;
        struct module *owner;
+       u32 flags;
        struct v4l2_device *v4l2_dev;
        const struct v4l2_subdev_ops *ops;
        /* name must be unique */
@@ -264,6 +268,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
        BUG_ON(!ops || !ops->core);
        sd->ops = ops;
        sd->v4l2_dev = NULL;
+       sd->flags = 0;
        sd->name[0] = '\0';
        sd->grp_id = 0;
        sd->priv = NULL;