Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Dec 2008 01:41:32 +0000 (17:41 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Dec 2008 01:41:32 +0000 (17:41 -0800)
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (583 commits)
  V4L/DVB (10130): use USB API functions rather than constants
  V4L/DVB (10129): dvb: remove deprecated use of RW_LOCK_UNLOCKED in frontends
  V4L/DVB (10128): modify V4L documentation to be a valid XHTML
  V4L/DVB (10127): stv06xx: Avoid having y unitialized
  V4L/DVB (10125): em28xx: Don't do AC97 vendor detection for i2s audio devices
  V4L/DVB (10124): em28xx: expand output formats available
  V4L/DVB (10123): em28xx: fix reversed definitions of I2S audio modes
  V4L/DVB (10122): em28xx: don't load em28xx-alsa for em2870 based devices
  V4L/DVB (10121): em28xx: remove worthless Pinnacle PCTV HD Mini 80e device profile
  V4L/DVB (10120): em28xx: remove redundant Pinnacle Dazzle DVC 100 profile
  V4L/DVB (10119): em28xx: fix corrupted XCLK value
  V4L/DVB (10118): zoran: fix warning for a variable not used
  V4L/DVB (10116): af9013: Fix gcc false warnings
  V4L/DVB (10111a): usbvideo.h: remove an useless blank line
  V4L/DVB (10111): quickcam_messenger.c: fix a warning
  V4L/DVB (10110): v4l2-ioctl: Fix warnings when using .unlocked_ioctl = __video_ioctl2
  V4L/DVB (10109): anysee: Fix usage of an unitialized function
  V4L/DVB (10104): uvcvideo: Add support for video output devices
  V4L/DVB (10102): uvcvideo: Ignore interrupt endpoint for built-in iSight webcams.
  V4L/DVB (10101): uvcvideo: Fix bulk URB processing when the header is erroneous
  ...

326 files changed:
Documentation/dvb/technisat.txt [new file with mode: 0644]
Documentation/video4linux/API.html
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/README.cx88
Documentation/video4linux/gspca.txt
Documentation/video4linux/v4l2-framework.txt [new file with mode: 0644]
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_video.c
drivers/media/common/tuners/mxl5005s.c
drivers/media/common/tuners/tda827x.c
drivers/media/common/tuners/tda8290.c
drivers/media/common/tuners/tda9887.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/Kconfig
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/cinergyT2-core.c
drivers/media/dvb/dvb-usb/cinergyT2.h
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/gp8psk-fe.c
drivers/media/dvb/dvb-usb/gp8psk.c
drivers/media/dvb/dvb-usb/gp8psk.h
drivers/media/dvb/dvb-usb/usb-urb.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/frontends/cx24113.c [new file with mode: 0644]
drivers/media/dvb/frontends/cx24113.h
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/dib7000p.h
drivers/media/dvb/frontends/drx397xD.c
drivers/media/dvb/frontends/drx397xD_fw.h
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/lgdt3304.c [new file with mode: 0644]
drivers/media/dvb/frontends/lgdt3304.h [new file with mode: 0644]
drivers/media/dvb/frontends/s5h1411.c
drivers/media/dvb/frontends/s921_core.c [new file with mode: 0644]
drivers/media/dvb/frontends/s921_core.h [new file with mode: 0644]
drivers/media/dvb/frontends/s921_module.c [new file with mode: 0644]
drivers/media/dvb/frontends/s921_module.h [new file with mode: 0644]
drivers/media/dvb/frontends/si21xx.c
drivers/media/dvb/frontends/stb0899_algo.c [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_cfg.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_drv.c [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_drv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_reg.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb6100.c [new file with mode: 0644]
drivers/media/dvb/frontends/stb6100.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb6100_cfg.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda8261.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda8261.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda8261_cfg.h [new file with mode: 0644]
drivers/media/dvb/frontends/zl10353.c
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/smsusb.c
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget.h
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/bt8xx/bt832.c [deleted file]
drivers/media/video/bt8xx/bt832.h [deleted file]
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-gpio.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/cpia.c
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_usb.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cs5345.c
drivers/media/video/cs53l32a.c
drivers/media/video/cx18/cx18-av-audio.c
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-core.h
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-cards.h
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-dvb.h
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-firmware.c
drivers/media/video/cx18/cx18-gpio.c
drivers/media/video/cx18/cx18-gpio.h
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-io.c
drivers/media/video/cx18/cx18-io.h
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-ioctl.h
drivers/media/video/cx18/cx18-irq.c
drivers/media/video/cx18/cx18-irq.h
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-queue.h
drivers/media/video/cx18/cx18-scb.c
drivers/media/video/cx18/cx18-scb.h
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-streams.h
drivers/media/video/cx18/cx18-vbi.c
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx18/cx23418.h
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25840/Kconfig
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-core.h
drivers/media/video/cx25840/cx25840-firmware.c
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-mpeg.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-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/etoms.c
drivers/media/video/gspca/finepix.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
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_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/mars.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c [new file with mode: 0644]
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca501.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca506.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/stv06xx/Kconfig [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/Makefile [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx.c [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx.h [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_sensor.h [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h [new file with mode: 0644]
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/tv8532.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/zc3xx-reg.h
drivers/media/video/gspca/zc3xx.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-cards.c
drivers/media/video/ivtv/ivtv-controls.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-gpio.h
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-i2c.h
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-routing.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/m52790.c
drivers/media/video/msp3400-driver.c
drivers/media/video/msp3400-driver.h
drivers/media/video/msp3400-kthreads.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t031.c [new file with mode: 0644]
drivers/media/video/mt9v022.c
drivers/media/video/omap24xxcam-dma.c [new file with mode: 0644]
drivers/media/video/omap24xxcam.c [new file with mode: 0644]
drivers/media/video/omap24xxcam.h [new file with mode: 0644]
drivers/media/video/ov511.c
drivers/media/video/ov772x.c [new file with mode: 0644]
drivers/media/video/pms.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.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/pwc/pwc.h
drivers/media/video/pxa_camera.c
drivers/media/video/saa5246a.c
drivers/media/video/saa5249.c
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa717x.c
drivers/media/video/se401.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/soc_camera.c
drivers/media/video/soc_camera_platform.c
drivers/media/video/stk-webcam.c
drivers/media/video/stv680.c
drivers/media/video/tda7432.c
drivers/media/video/tda9840.c
drivers/media/video/tda9875.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/tlv320aic23b.c
drivers/media/video/tuner-core.c
drivers/media/video/tvaudio.c
drivers/media/video/tvp514x.c [new file with mode: 0644]
drivers/media/video/tvp514x_regs.h [new file with mode: 0644]
drivers/media/video/tvp5150.c
drivers/media/video/tw9910.c [new file with mode: 0644]
drivers/media/video/upd64031a.c
drivers/media/video/upd64083.c
drivers/media/video/usbvideo/ibmcam.c
drivers/media/video/usbvideo/konicawc.c
drivers/media/video/usbvideo/quickcam_messenger.c
drivers/media/video/usbvideo/ultracam.c
drivers/media/video/usbvideo/usbvideo.c
drivers/media/video/usbvideo/vicam.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_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-compat-ioctl32.c [moved from drivers/media/video/compat_ioctl32.c with 53% similarity]
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-device.c [new file with mode: 0644]
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-subdev.c [new file with mode: 0644]
drivers/media/video/vino.c
drivers/media/video/vp27smpx.c
drivers/media/video/w9966.c
drivers/media/video/wm8739.c
drivers/media/video/wm8775.c
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zoran/zoran_driver.c
firmware/Makefile
include/linux/videodev2.h
include/media/i2c-addr.h
include/media/ir-common.h
include/media/ov772x.h [new file with mode: 0644]
include/media/saa7146_vv.h
include/media/soc_camera.h
include/media/tvp514x.h [new file with mode: 0644]
include/media/tw9910.h [new file with mode: 0644]
include/media/v4l2-chip-ident.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-device.h [new file with mode: 0644]
include/media/v4l2-int-device.h
include/media/v4l2-ioctl.h
include/media/v4l2-subdev.h [new file with mode: 0644]
sound/i2c/other/tea575x-tuner.c

diff --git a/Documentation/dvb/technisat.txt b/Documentation/dvb/technisat.txt
new file mode 100644 (file)
index 0000000..cdf6ee4
--- /dev/null
@@ -0,0 +1,69 @@
+How to set up the Technisat devices
+===================================
+
+1) Find out what device you have
+================================
+
+First start your linux box with a shipped kernel:
+lspci -vvv for a PCI device (lsusb -vvv for an USB device) will show you for example:
+02:0b.0 Network controller: Techsan Electronics Co Ltd B2C2 FlexCopII DVB chip / Technisat SkyStar2 DVB card (rev 02)
+
+dmesg | grep frontend may show you for example:
+DVB: registering frontend 0 (Conexant CX24123/CX24109)...
+
+2) Kernel compilation:
+======================
+
+If the Technisat is the only TV device in your box get rid of unnecessary modules and check this one:
+"Multimedia devices" => "Customise analog and hybrid tuner modules to build"
+In this directory uncheck every driver which is activated there.
+
+Then please activate:
+2a) Main module part:
+
+a.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters"
+b.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC PCI" in case of a PCI card OR
+c.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC USB" in case of an USB 1.1 adapter
+d.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Enable debug for the B2C2 FlexCop drivers"
+Notice: d.) is helpful for troubleshooting
+
+2b) Frontend module part:
+
+1.) Revision 2.3:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink VP310/MT312/ZL10313 based"
+
+2.) Revision 2.6:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0299 based"
+
+3.) Revision 2.7:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Samsung S5H1420 based"
+c.)"Multimedia devices" => "Customise DVB frontends" => "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
+d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller"
+
+4.) Revision 2.8:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
+c.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24123 based"
+d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller"
+
+5.) DVB-T card:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink MT352 based"
+
+6.) DVB-C card:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0297 based"
+
+7.) ATSC card 1st generation:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Broadcom BCM3510"
+
+8.) ATSC card 2nd generation:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "NxtWave Communications NXT2002/NXT2004 based"
+c.)"Multimedia devices" => "Customise DVB frontends" => "LG Electronics LGDT3302/LGDT3303 based"
+
+Author: Uwe Bugla <uwe.bugla@gmx.de> December 2008
index afbe9ae7ee9682c6b4377efc8b7e8a80d3fe1087..d749d41f647b145df62780ef7820a1de23fee80d 100644 (file)
@@ -1,16 +1,27 @@
-<TITLE>V4L API</TITLE>
-<H1>Video For Linux APIs</H1>
-<table border=0>
-<tr>
-<td>
-<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html>
-V4L original API</a>
-</td><td>
-Obsoleted by V4L2 API
-</td></tr><tr><td>
-<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API>
-V4L2 API</a>
-</td><td>
-Should be used for new projects
-</td></tr>
-</table>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+  <meta content="text/html;charset=ISO-8859-2" http-equiv="Content-Type" />
+  <title>V4L API</title>
+ </head>
+ <body>
+  <h1>Video For Linux APIs</h1>
+  <table border="0">
+   <tr>
+    <td>
+     <a href="http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html">V4L original API</a>
+    </td>
+    <td>
+     Obsoleted by V4L2 API
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <a href="http://www.linuxtv.org/downloads/video4linux/API/V4L2_API">V4L2 API</a>
+    </td>
+    <td>Should be used for new projects
+    </td>
+   </tr>
+  </table>
+ </body>
+</html>
index 60ba66836038215952c9be46dcbff58edb19b319..0d93fa1ac25e344311ca53d71adb859c24984b52 100644 (file)
 103 -> Grand X-Guard / Trust 814PCI                        [0304:0102]
 104 -> Nebula Electronics DigiTV                           [0071:0101]
 105 -> ProVideo PV143                                      [aa00:1430,aa00:1431,aa00:1432,aa00:1433,aa03:1433]
-106 -> PHYTEC VD-009-X1 MiniDIN (bt878)
-107 -> PHYTEC VD-009-X1 Combi (bt878)
+106 -> PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)
+107 -> PHYTEC VD-009-X1 VD-011 Combi (bt878)
 108 -> PHYTEC VD-009 MiniDIN (bt878)
 109 -> PHYTEC VD-009 Combi (bt878)
 110 -> IVC-100                                             [ff00:a132]
 150 -> Geovision GV-600                                    [008a:763c]
 151 -> Kozumi KTV-01C
 152 -> Encore ENL TV-FM-2                                  [1000:1801]
+153 -> PHYTEC VD-012 (bt878)
+154 -> PHYTEC VD-012-X1 (bt878)
+155 -> PHYTEC VD-012-X2 (bt878)
index 64823ccacd69013ae48401705e7704a39ce38136..35ea130e9898c21231347559f601ea572687cb08 100644 (file)
@@ -11,3 +11,4 @@
  10 -> DViCO FusionHDTV7 Dual Express                      [18ac:d618]
  11 -> DViCO FusionHDTV DVB-T Dual Express                 [18ac:db78]
  12 -> Leadtek Winfast PxDVR3200 H                         [107d:6681]
+ 13 -> Compro VideoMate E650F                              [185b:e800]
index a5227e308f4ab91146dc2426a2bd694d95d63043..0d08f1edcf6d1d978dbfd6265b17126bb87fe96f 100644 (file)
@@ -2,7 +2,7 @@
   1 -> Hauppauge WinTV 34xxx models                        [0070:3400,0070:3401]
   2 -> GDI Black Gold                                      [14c7:0106,14c7:0107]
   3 -> PixelView                                           [1554:4811]
-  4 -> ATI TV Wonder Pro                                   [1002:00f8]
+  4 -> ATI TV Wonder Pro                                   [1002:00f8,1002:00f9]
   5 -> Leadtek Winfast 2000XP Expert                       [107d:6611,107d:6613]
   6 -> AverTV Studio 303 (M126)                            [1461:000b]
   7 -> MSI TV-@nywhere Master                              [1462:8606]
@@ -74,3 +74,6 @@
  73 -> TeVii S420 DVB-S                                    [d420:9022]
  74 -> Prolink Pixelview Global Extreme                    [1554:4976]
  75 -> PROF 7300 DVB-S/S2                                  [B033:3033]
+ 76 -> SATTRADE ST4200 DVB-S/S2                            [b200:4200]
+ 77 -> TBS 8910 DVB-S                                      [8910:8888]
+ 78 -> Prof 6200 DVB-S                                     [b022:3022]
index 187cc48d092469a045ccd52fb16d4239bf6c447e..75bded8a4aa2e449b09c4454da01b3eeae76d022 100644 (file)
@@ -1,5 +1,5 @@
   0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
-  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2820,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
+  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
   2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
   3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
   4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200,2040:4201]
@@ -12,9 +12,9 @@
  11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
  13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
- 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840) [eb1a:2821]
+ 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
  15 -> V-Gear PocketTV                          (em2800)
- 16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b,2040:651f]
+ 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)
@@ -27,7 +27,6 @@
  26 -> Hercules Smart TV USB 2.0                (em2820/em2840)
  27 -> Pinnacle PCTV USB 2 (Philips FM1216ME)   (em2820/em2840)
  28 -> Leadtek Winfast USB II Deluxe            (em2820/em2840)
- 29 -> Pinnacle Dazzle DVC 100                  (em2820/em2840)
  30 -> Videology 20K14XUSB USB2.0               (em2820/em2840)
  31 -> Usbgear VD204v9                          (em2821)
  32 -> Supercomp USB 2.0 TV                     (em2821)
@@ -57,3 +56,5 @@
  56 -> Pinnacle Hybrid Pro (2)                  (em2882)        [2304:0226]
  57 -> Kworld PlusTV HD Hybrid 330              (em2883)        [eb1a:a316]
  58 -> Compro VideoMate ForYou/Stereo           (em2820/em2840) [185b:2041]
+ 60 -> Hauppauge WinTV HVR 850                  (em2883)        [2040:651f]
+ 61 -> Pixelview PlayTV Box 4 USB 2.0           (em2820/em2840)
index dc67eef38ff92071995b9c0d12f901ef4e3837b9..335aef4dcaebdaa0acf87477865a0b0cea9be377 100644 (file)
@@ -10,7 +10,7 @@
   9 -> Medion 5044
  10 -> Kworld/KuroutoShikou SAA7130-TVPCI
  11 -> Terratec Cinergy 600 TV                  [153b:1143]
- 12 -> Medion 7134                              [16be:0003]
+ 12 -> Medion 7134                              [16be:0003,16be:5000]
  13 -> Typhoon TV+Radio 90031
  14 -> ELSA EX-VISION 300TV                     [1048:226b]
  15 -> ELSA EX-VISION 500TV                     [1048:226a]
 150 -> Zogis Real Angel 220
 151 -> ADS Tech Instant HDTV                    [1421:0380]
 152 -> Asus Tiger Rev:1.00                      [1043:4857]
+153 -> Kworld Plus TV Analog Lite PCI           [17de:7128]
index 166d5960b1a97b83caac3e00484f9f8f00b5ae4f..35fae23f883b6090c438b2bd707beb09ec9b2a8c 100644 (file)
@@ -1,4 +1,3 @@
-
 cx8800 release notes
 ====================
 
@@ -10,21 +9,20 @@ current status
 
 video
        - Basically works.
-       - Some minor image quality glitches.
-       - For now only capture, overlay support isn't completed yet.
+       - For now, only capture and read(). Overlay isn't supported.
 
 audio
        - The chip specs for the on-chip TV sound decoder are next
          to useless :-/
        - Neverless the builtin TV sound decoder starts working now,
-         at least for PAL-BG.  Other TV norms need other code ...
+         at least for some standards.
          FOR ANY REPORTS ON THIS PLEASE MENTION THE TV NORM YOU ARE
          USING.
        - Most tuner chips do provide mono sound, which may or may not
          be useable depending on the board design.  With the Hauppauge
          cards it works, so there is mono sound available as fallback.
        - audio data dma (i.e. recording without loopback cable to the
-         sound card) should be possible, but there is no code yet ...
+         sound card) is supported via cx88-alsa.
 
 vbi
        - Code present. Works for NTSC closed caption. PAL and other
index 004818fab040ab0bb04078be639c5346a688f772..1c58a763014646182a17aa50efb5dc19b01425f3 100644 (file)
@@ -50,9 +50,14 @@ ov519                045e:028c       Micro$oft xbox cam
 spca508                0461:0815       Micro Innovation IC200
 sunplus                0461:0821       Fujifilm MV-1
 zc3xx          0461:0a00       MicroInnovation WebCam320
+stv06xx                046d:0840       QuickCam Express
+stv06xx                046d:0850       LEGO cam / QuickCam Web
+stv06xx                046d:0870       Dexxa WebCam USB
 spca500                046d:0890       Logitech QuickCam traveler
 vc032x         046d:0892       Logitech Orbicam
 vc032x         046d:0896       Logitech Orbicam
+vc032x         046d:0897       Logitech QuickCam for Dell notebooks
+zc3xx          046d:089d       Logitech QuickCam E2500
 zc3xx          046d:08a0       Logitech QC IM
 zc3xx          046d:08a1       Logitech QC IM 0x08A1 +sound
 zc3xx          046d:08a2       Labtec Webcam Pro
@@ -169,6 +174,9 @@ spca500             06bd:0404       Agfa CL20
 spca500                06be:0800       Optimedia
 sunplus                06d6:0031       Trust 610 LCD PowerC@m Zoom
 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
 spca508                0733:0110       ViewQuest VQ110
 spca508                0130:0130       Clone Digital Webcam 11043
 spca501                0733:0401       Intel Create and Share
@@ -199,7 +207,8 @@ sunplus             08ca:2050       Medion MD 41437
 sunplus                08ca:2060       Aiptek PocketDV5300
 tv8532         0923:010f       ICM532 cams
 mars           093a:050f       Mars-Semi Pc-Camera
-pac207         093a:2460       PAC207 Qtec Webcam 100
+pac207         093a:2460       Qtec Webcam 100
+pac207         093a:2461       HP Webcam
 pac207         093a:2463       Philips SPC 220 NC
 pac207         093a:2464       Labtec Webcam 1200
 pac207         093a:2468       PAC207
@@ -213,10 +222,13 @@ pac7311           093a:2603       PAC7312
 pac7311                093a:2608       Trust WB-3300p
 pac7311                093a:260e       Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
 pac7311                093a:260f       SnakeCam
+pac7311                093a:2620       Apollo AC-905
 pac7311                093a:2621       PAC731x
+pac7311                093a:2622       Genius Eye 312
 pac7311                093a:2624       PAC7302
 pac7311                093a:2626       Labtec 2200
 pac7311                093a:262a       Webcam 300k
+pac7311                093a:262c       Philips SPC 230 NC
 zc3xx          0ac8:0302       Z-star Vimicro zc0302
 vc032x         0ac8:0321       Vimicro generic vc0321
 vc032x         0ac8:0323       Vimicro Vc0323
@@ -249,11 +261,13 @@ sonixj            0c45:60c0       Sangha Sn535
 sonixj         0c45:60ec       SN9C105+MO4000
 sonixj         0c45:60fb       Surfer NoName
 sonixj         0c45:60fc       LG-LIC300
+sonixj         0c45:60fe       Microdia Audio
 sonixj         0c45:6128       Microdia/Sonix SNP325
 sonixj         0c45:612a       Avant Camera
 sonixj         0c45:612c       Typhoon Rasy Cam 1.3MPix
 sonixj         0c45:6130       Sonix Pccam
 sonixj         0c45:6138       Sn9c120 Mo4000
+sonixj         0c45:613a       Microdia Sonix PC Camera
 sonixj         0c45:613b       Surfer SN-206
 sonixj         0c45:613c       Sonix Pccam168
 sonixj         0c45:6143       Sonix Pccam168
@@ -263,6 +277,9 @@ etoms               102c:6251       Qcam xxxxxx VGA
 zc3xx          10fd:0128       Typhoon Webshot II USB 300k 0x0128
 spca561                10fd:7e50       FlyCam Usb 100
 zc3xx          10fd:8050       Typhoon Webshot II USB 300k
+ov534          1415:2000       Sony HD Eye for PS3 (SLEH 00201)
+pac207         145f:013a       Trust WB-1300N
+vc032x         15b8:6002       HP 2.0 Megapixel rz406aa
 spca501                1776:501c       Arowana 300K CMOS Camera
 t613           17a1:0128       TASCORP JPEG Webcam, NGS Cyclops
 vc032x         17ef:4802       Lenovo Vc0323+MI1310_SOC
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
new file mode 100644 (file)
index 0000000..eeae76c
--- /dev/null
@@ -0,0 +1,520 @@
+Overview of the V4L2 driver framework
+=====================================
+
+This text documents the various structures provided by the V4L2 framework and
+their relationships.
+
+
+Introduction
+------------
+
+The V4L2 drivers tend to be very complex due to the complexity of the
+hardware: most devices have multiple ICs, export multiple device nodes in
+/dev, and create also non-V4L2 devices such as DVB, ALSA, FB, I2C and input
+(IR) devices.
+
+Especially the fact that V4L2 drivers have to setup supporting ICs to
+do audio/video muxing/encoding/decoding makes it more complex than most.
+Usually these ICs are connected to the main bridge driver through one or
+more I2C busses, but other busses can also be used. Such devices are
+called 'sub-devices'.
+
+For a long time the framework was limited to the video_device struct for
+creating V4L device nodes and video_buf for handling the video buffers
+(note that this document does not discuss the video_buf framework).
+
+This meant that all drivers had to do the setup of device instances and
+connecting to sub-devices themselves. Some of this is quite complicated
+to do right and many drivers never did do it correctly.
+
+There is also a lot of common code that could never be refactored due to
+the lack of a framework.
+
+So this framework sets up the basic building blocks that all drivers
+need and this same framework should make it much easier to refactor
+common code into utility functions shared by all drivers.
+
+
+Structure of a driver
+---------------------
+
+All drivers have the following structure:
+
+1) A struct for each device instance containing the device state.
+
+2) A way of initializing and commanding sub-devices (if any).
+
+3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX, /dev/radioX and
+   /dev/vtxX) and keeping track of device-node specific data.
+
+4) Filehandle-specific structs containing per-filehandle data.
+
+This is a rough schematic of how it all relates:
+
+    device instances
+      |
+      +-sub-device instances
+      |
+      \-V4L2 device nodes
+         |
+         \-filehandle instances
+
+
+Structure of the framework
+--------------------------
+
+The framework closely resembles the driver structure: it has a v4l2_device
+struct for the device instance data, a v4l2_subdev struct to refer to
+sub-device instances, the video_device struct stores V4L2 device node data
+and in the future a v4l2_fh struct will keep track of filehandle instances
+(this is not yet implemented).
+
+
+struct v4l2_device
+------------------
+
+Each device instance is represented by a struct v4l2_device (v4l2-device.h).
+Very simple devices can just allocate this struct, but most of the time you
+would embed this struct inside a larger struct.
+
+You must register the device instance:
+
+       v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+
+Registration will initialize the v4l2_device struct and link dev->driver_data
+to v4l2_dev. Registration will also set v4l2_dev->name to a value derived from
+dev (driver name followed by the bus_id, to be precise). You may change the
+name after registration if you want.
+
+The first 'dev' argument is normally the struct device pointer of a pci_dev,
+usb_device or platform_device.
+
+You unregister with:
+
+       v4l2_device_unregister(struct v4l2_device *v4l2_dev);
+
+Unregistering will also automatically unregister all subdevs from the device.
+
+Sometimes you need to iterate over all devices registered by a specific
+driver. This is usually the case if multiple device drivers use the same
+hardware. E.g. the ivtvfb driver is a framebuffer driver that uses the ivtv
+hardware. The same is true for alsa drivers for example.
+
+You can iterate over all registered devices as follows:
+
+static int callback(struct device *dev, void *p)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+
+       /* test if this device was inited */
+       if (v4l2_dev == NULL)
+               return 0;
+       ...
+       return 0;
+}
+
+int iterate(void *p)
+{
+       struct device_driver *drv;
+       int err;
+
+       /* Find driver 'ivtv' on the PCI bus.
+          pci_bus_type is a global. For USB busses use usb_bus_type. */
+       drv = driver_find("ivtv", &pci_bus_type);
+       /* iterate over all ivtv device instances */
+       err = driver_for_each_device(drv, NULL, p, callback);
+       put_driver(drv);
+       return err;
+}
+
+Sometimes you need to keep a running counter of the device instance. This is
+commonly used to map a device instance to an index of a module option array.
+
+The recommended approach is as follows:
+
+static atomic_t drv_instance = ATOMIC_INIT(0);
+
+static int __devinit drv_probe(struct pci_dev *dev,
+                               const struct pci_device_id *pci_id)
+{
+       ...
+       state->instance = atomic_inc_return(&drv_instance) - 1;
+}
+
+
+struct v4l2_subdev
+------------------
+
+Many drivers need to communicate with sub-devices. These devices can do all
+sort of tasks, but most commonly they handle audio and/or video muxing,
+encoding or decoding. For webcams common sub-devices are sensors and camera
+controllers.
+
+Usually these are I2C devices, but not necessarily. In order to provide the
+driver with a consistent interface to these sub-devices the v4l2_subdev struct
+(v4l2-subdev.h) was created.
+
+Each sub-device driver must have a v4l2_subdev struct. This struct can be
+stand-alone for simple sub-devices or it might be embedded in a larger struct
+if more state information needs to be stored. Usually there is a low-level
+device struct (e.g. i2c_client) that contains the device data as setup
+by the kernel. It is recommended to store that pointer in the private
+data of v4l2_subdev using v4l2_set_subdevdata(). That makes it easy to go
+from a v4l2_subdev to the actual low-level bus-specific device data.
+
+You also need a way to go from the low-level struct to v4l2_subdev. For the
+common i2c_client struct the i2c_set_clientdata() call is used to store a
+v4l2_subdev pointer, for other busses you may have to use other methods.
+
+From the bridge driver perspective you load the sub-device module and somehow
+obtain the v4l2_subdev pointer. For i2c devices this is easy: you call
+i2c_get_clientdata(). For other busses something similar needs to be done.
+Helper functions exists for sub-devices on an I2C bus that do most of this
+tricky work for you.
+
+Each v4l2_subdev contains function pointers that sub-device drivers can
+implement (or leave NULL if it is not applicable). Since sub-devices can do
+so many different things and you do not want to end up with a huge ops struct
+of which only a handful of ops are commonly implemented, the function pointers
+are sorted according to category and each category has its own ops struct.
+
+The top-level ops struct contains pointers to the category ops structs, which
+may be NULL if the subdev driver does not support anything from that category.
+
+It looks like this:
+
+struct v4l2_subdev_core_ops {
+       int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip);
+       int (*log_status)(struct v4l2_subdev *sd);
+       int (*init)(struct v4l2_subdev *sd, u32 val);
+       ...
+};
+
+struct v4l2_subdev_tuner_ops {
+       ...
+};
+
+struct v4l2_subdev_audio_ops {
+       ...
+};
+
+struct v4l2_subdev_video_ops {
+       ...
+};
+
+struct v4l2_subdev_ops {
+       const struct v4l2_subdev_core_ops  *core;
+       const struct v4l2_subdev_tuner_ops *tuner;
+       const struct v4l2_subdev_audio_ops *audio;
+       const struct v4l2_subdev_video_ops *video;
+};
+
+The core ops are common to all subdevs, the other categories are implemented
+depending on the sub-device. E.g. a video device is unlikely to support the
+audio ops and vice versa.
+
+This setup limits the number of function pointers while still making it easy
+to add new ops and categories.
+
+A sub-device driver initializes the v4l2_subdev struct using:
+
+       v4l2_subdev_init(subdev, &ops);
+
+Afterwards you need to initialize subdev->name with a unique name and set the
+module owner. This is done for you if you use the i2c helper functions.
+
+A device (bridge) driver needs to register the v4l2_subdev with the
+v4l2_device:
+
+       int err = v4l2_device_register_subdev(device, subdev);
+
+This can fail if the subdev module disappeared before it could be registered.
+After this function was called successfully the subdev->dev field points to
+the v4l2_device.
+
+You can unregister a sub-device using:
+
+       v4l2_device_unregister_subdev(subdev);
+
+Afterwards the subdev module can be unloaded and subdev->dev == NULL.
+
+You can call an ops function either directly:
+
+       err = subdev->ops->core->g_chip_ident(subdev, &chip);
+
+but it is better and easier to use this macro:
+
+       err = v4l2_subdev_call(subdev, core, g_chip_ident, &chip);
+
+The macro will to the right NULL pointer checks and returns -ENODEV if subdev
+is NULL, -ENOIOCTLCMD if either subdev->core or subdev->core->g_chip_ident is
+NULL, or the actual result of the subdev->ops->core->g_chip_ident ops.
+
+It is also possible to call all or a subset of the sub-devices:
+
+       v4l2_device_call_all(dev, 0, core, g_chip_ident, &chip);
+
+Any subdev that does not support this ops is skipped and error results are
+ignored. If you want to check for errors use this:
+
+       err = v4l2_device_call_until_err(dev, 0, core, g_chip_ident, &chip);
+
+Any error except -ENOIOCTLCMD will exit the loop with that error. If no
+errors (except -ENOIOCTLCMD) occured, then 0 is returned.
+
+The second argument to both calls is a group ID. If 0, then all subdevs are
+called. If non-zero, then only those whose group ID match that value will
+be called. Before a bridge driver registers a subdev it can set subdev->grp_id
+to whatever value it wants (it's 0 by default). This value is owned by the
+bridge driver and the sub-device driver will never modify or use it.
+
+The group ID gives the bridge driver more control how callbacks are called.
+For example, there may be multiple audio chips on a board, each capable of
+changing the volume. But usually only one will actually be used when the
+user want to change the volume. You can set the group ID for that subdev to
+e.g. AUDIO_CONTROLLER and specify that as the group ID value when calling
+v4l2_device_call_all(). That ensures that it will only go to the subdev
+that needs it.
+
+The advantage of using v4l2_subdev is that it is a generic struct and does
+not contain any knowledge about the underlying hardware. So a driver might
+contain several subdevs that use an I2C bus, but also a subdev that is
+controlled through GPIO pins. This distinction is only relevant when setting
+up the device, but once the subdev is registered it is completely transparent.
+
+
+I2C sub-device drivers
+----------------------
+
+Since these drivers are so common, special helper functions are available to
+ease the use of these drivers (v4l2-common.h).
+
+The recommended method of adding v4l2_subdev support to an I2C driver is to
+embed the v4l2_subdev struct into the state struct that is created for each
+I2C device instance. Very simple devices have no state struct and in that case
+you can just create a v4l2_subdev directly.
+
+A typical state struct would look like this (where 'chipname' is replaced by
+the name of the chip):
+
+struct chipname_state {
+       struct v4l2_subdev sd;
+       ...  /* additional state fields */
+};
+
+Initialize the v4l2_subdev struct as follows:
+
+       v4l2_i2c_subdev_init(&state->sd, client, subdev_ops);
+
+This function will fill in all the fields of v4l2_subdev and ensure that the
+v4l2_subdev and i2c_client both point to one another.
+
+You should also add a helper inline function to go from a v4l2_subdev pointer
+to a chipname_state struct:
+
+static inline struct chipname_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct chipname_state, sd);
+}
+
+Use this to go from the v4l2_subdev struct to the i2c_client struct:
+
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+And this to go from an i2c_client to a v4l2_subdev struct:
+
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+Finally you need to make a command function to make driver->command()
+call the right subdev_ops functions:
+
+static int subdev_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+If driver->command is never used then you can leave this out. Eventually the
+driver->command usage should be removed from v4l.
+
+Make sure to call v4l2_device_unregister_subdev(sd) when the remove() callback
+is called. This will unregister the sub-device from the bridge driver. It is
+safe to call this even if the sub-device was never registered.
+
+
+The bridge driver also has some helper functions it can use:
+
+struct v4l2_subdev *sd = v4l2_i2c_new_subdev(adapter, "module_foo", "chipid", 0x36);
+
+This loads the given module (can be NULL if no module needs to be loaded) and
+calls i2c_new_device() with the given i2c_adapter and chip/address arguments.
+If all goes well, then it registers the subdev with the v4l2_device. It gets
+the v4l2_device by calling i2c_get_adapdata(adapter), so you should make sure
+that adapdata is set to v4l2_device when you setup the i2c_adapter in your
+driver.
+
+You can also use v4l2_i2c_new_probed_subdev() which is very similar to
+v4l2_i2c_new_subdev(), except that it has an array of possible I2C addresses
+that it should probe. Internally it calls i2c_new_probed_device().
+
+Both functions return NULL if something went wrong.
+
+
+struct video_device
+-------------------
+
+The actual device nodes in the /dev directory are created using the
+video_device struct (v4l2-dev.h). This struct can either be allocated
+dynamically or embedded in a larger struct.
+
+To allocate it dynamically use:
+
+       struct video_device *vdev = video_device_alloc();
+
+       if (vdev == NULL)
+               return -ENOMEM;
+
+       vdev->release = video_device_release;
+
+If you embed it in a larger struct, then you must set the release()
+callback to your own function:
+
+       struct video_device *vdev = &my_vdev->vdev;
+
+       vdev->release = my_vdev_release;
+
+The release callback must be set and it is called when the last user
+of the video device exits.
+
+The default video_device_release() callback just calls kfree to free the
+allocated memory.
+
+You should also set these fields:
+
+- parent: set to the parent device (same device as was used to register
+  v4l2_device).
+- name: set to something descriptive and unique.
+- fops: set to the file_operations struct.
+- ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
+  (highly recommended to use this and it might become compulsory in the
+  future!), then set this to your v4l2_ioctl_ops struct.
+
+If you use v4l2_ioctl_ops, then you should set .unlocked_ioctl to
+__video_ioctl2 or .ioctl to video_ioctl2 in your file_operations struct.
+
+
+video_device registration
+-------------------------
+
+Next you register the video device: this will create the character device
+for you.
+
+       err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       if (err) {
+               video_device_release(vdev); // or kfree(my_vdev);
+               return err;
+       }
+
+Which device is registered depends on the type argument. The following
+types exist:
+
+VFL_TYPE_GRABBER: videoX for video input/output devices
+VFL_TYPE_VBI: vbiX for vertical blank data (i.e. closed captions, teletext)
+VFL_TYPE_RADIO: radioX for radio tuners
+VFL_TYPE_VTX: vtxX for teletext devices (deprecated, don't use)
+
+The last argument gives you a certain amount of control over the device
+kernel number used (i.e. the X in videoX). Normally you will pass -1 to
+let the v4l2 framework pick the first free number. But if a driver creates
+many devices, then it can be useful to have different video devices in
+separate ranges. For example, video capture devices start at 0, video
+output devices start at 16.
+
+So you can use the last argument to specify a minimum kernel number and
+the v4l2 framework will try to pick the first free number that is equal
+or higher to what you passed. If that fails, then it will just pick the
+first free number.
+
+Whenever a device node is created some attributes are also created for you.
+If you look in /sys/class/video4linux you see the devices. Go into e.g.
+video0 and you will see 'name' and 'index' attributes. The 'name' attribute
+is the 'name' field of the video_device struct. The 'index' attribute is
+a device node index that can be assigned by the driver, or that is calculated
+for you.
+
+If you call video_register_device(), then the index is just increased by
+1 for each device node you register. The first video device node you register
+always starts off with 0.
+
+Alternatively you can call video_register_device_index() which is identical
+to video_register_device(), but with an extra index argument. Here you can
+pass a specific index value (between 0 and 31) that should be used.
+
+Users can setup udev rules that utilize the index attribute to make fancy
+device names (e.g. 'mpegX' for MPEG video capture device nodes).
+
+After the device was successfully registered, then you can use these fields:
+
+- vfl_type: the device type passed to video_register_device.
+- minor: the assigned device minor number.
+- num: the device kernel number (i.e. the X in videoX).
+- index: the device index number (calculated or set explicitly using
+  video_register_device_index).
+
+If the registration failed, then you need to call video_device_release()
+to free the allocated video_device struct, or free your own struct if the
+video_device was embedded in it. The vdev->release() callback will never
+be called if the registration failed, nor should you ever attempt to
+unregister the device if the registration failed.
+
+
+video_device cleanup
+--------------------
+
+When the video device nodes have to be removed, either during the unload
+of the driver or because the USB device was disconnected, then you should
+unregister them:
+
+       video_unregister_device(vdev);
+
+This will remove the device nodes from sysfs (causing udev to remove them
+from /dev).
+
+After video_unregister_device() returns no new opens can be done.
+
+However, in the case of USB devices some application might still have one
+of these device nodes open. You should block all new accesses to read,
+write, poll, etc. except possibly for certain ioctl operations like
+queueing buffers.
+
+When the last user of the video device node exits, then the vdev->release()
+callback is called and you can do the final cleanup there.
+
+
+video_device helper functions
+-----------------------------
+
+There are a few useful helper functions:
+
+You can set/get driver private data in the video_device struct using:
+
+void *video_get_drvdata(struct video_device *dev);
+void video_set_drvdata(struct video_device *dev, void *data);
+
+Note that you can safely call video_set_drvdata() before calling
+video_register_device().
+
+And this function:
+
+struct video_device *video_devdata(struct file *file);
+
+returns the video_device belonging to the file struct.
+
+The final helper function combines video_get_drvdata with
+video_devdata:
+
+void *video_drvdata(struct file *file);
+
+You can go from a video_device struct to the v4l2_device struct using:
+
+struct v4l2_device *v4l2_dev = dev_get_drvdata(vdev->parent);
+
index 4952aeb5dd80583ba34c4bff94ee319ddf1a4731..d8229a0e9a9c4754603bb8cf0bfefd05e72ad36e 100644 (file)
@@ -2391,6 +2391,67 @@ IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
 };
 EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
 
+/* Kworld Plus TV Analog Lite PCI IR
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
+       [0x0c] = KEY_PROG1,             /* Kworld key */
+       [0x16] = KEY_CLOSECD,           /* -> ) */
+       [0x1d] = KEY_POWER2,
+
+       [0x00] = KEY_1,
+       [0x01] = KEY_2,
+       [0x02] = KEY_3,                 /* Two keys have the same code: 3 and left */
+       [0x03] = KEY_4,                 /* Two keys have the same code: 3 and right */
+       [0x04] = KEY_5,
+       [0x05] = KEY_6,
+       [0x06] = KEY_7,
+       [0x07] = KEY_8,
+       [0x08] = KEY_9,
+       [0x0a] = KEY_0,
+
+       [0x09] = KEY_AGAIN,
+       [0x14] = KEY_MUTE,
+
+       [0x20] = KEY_UP,
+       [0x21] = KEY_DOWN,
+       [0x0b] = KEY_ENTER,
+
+       [0x10] = KEY_CHANNELUP,
+       [0x11] = KEY_CHANNELDOWN,
+
+       /* Couldn't map key left/key right since those
+          conflict with '3' and '4' scancodes
+          I dunno what the original driver does
+        */
+
+       [0x13] = KEY_VOLUMEUP,
+       [0x12] = KEY_VOLUMEDOWN,
+
+       /* The lower part of the IR
+          There are several duplicated keycodes there.
+          Most of them conflict with digits.
+          Add mappings just to the unused scancodes.
+          Somehow, the original driver has a way to know,
+          but this doesn't seem to be on some GPIO.
+          Also, it is not related to the time between keyup
+          and keydown.
+        */
+       [0x19] = KEY_PAUSE,             /* Timeshift */
+       [0x1a] = KEY_STOP,
+       [0x1b] = KEY_RECORD,
+
+       [0x22] = KEY_TEXT,
+
+       [0x15] = KEY_AUDIO,             /* ((*)) */
+       [0x0f] = KEY_ZOOM,
+       [0x1c] = KEY_SHUFFLE,           /* snapshot */
+
+       [0x18] = KEY_RED,               /* B */
+       [0x23] = KEY_GREEN,             /* C */
+};
+EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog);
+
 IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
        [0x20] = KEY_LIST,
        [0x00] = KEY_POWER,
@@ -2511,3 +2572,35 @@ IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = {
 
 };
 EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys);
+
+/* ATI TV Wonder HD 600 USB
+   Devin Heitmueller <devin.heitmueller@gmail.com>
+ */
+IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE] = {
+       [0x00] = KEY_RECORD,            /* Row 1 */
+       [0x01] = KEY_PLAYPAUSE,
+       [0x02] = KEY_STOP,
+       [0x03] = KEY_POWER,
+       [0x04] = KEY_PREVIOUS,  /* Row 2 */
+       [0x05] = KEY_REWIND,
+       [0x06] = KEY_FORWARD,
+       [0x07] = KEY_NEXT,
+       [0x08] = KEY_EPG,               /* Row 3 */
+       [0x09] = KEY_HOME,
+       [0x0a] = KEY_MENU,
+       [0x0b] = KEY_CHANNELUP,
+       [0x0c] = KEY_BACK,              /* Row 4 */
+       [0x0d] = KEY_UP,
+       [0x0e] = KEY_INFO,
+       [0x0f] = KEY_CHANNELDOWN,
+       [0x10] = KEY_LEFT,              /* Row 5 */
+       [0x11] = KEY_SELECT,
+       [0x12] = KEY_RIGHT,
+       [0x13] = KEY_VOLUMEUP,
+       [0x14] = KEY_LAST,              /* Row 6 */
+       [0x15] = KEY_DOWN,
+       [0x16] = KEY_MUTE,
+       [0x17] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600);
index 127b0526a727f15ac9bf6f570e05ac0f352c08a7..7d844af883848a46c5eb99b8b25afbef6fbe46c3 100644 (file)
@@ -313,7 +313,7 @@ static int fops_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 /*
        DEB_EE(("inode:%p, file:%p, cmd:%d, arg:%li\n",inode, file, cmd, arg));
 */
-       return video_usercopy(inode, file, cmd, arg, saa7146_video_do_ioctl);
+       return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl);
 }
 
 static int fops_mmap(struct file *file, struct vm_area_struct * vma)
index fe0bd55977e32a1c1858597ffcbf53314eec2071..101b01dbb8eaf11b3c8960ea31e8ec42182e0cad 100644 (file)
@@ -834,7 +834,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
  * copying is done already, arg is a kernel pointer.
  */
 
-static int __saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+int saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct saa7146_fh *fh  = file->private_data;
        struct saa7146_dev *dev = fh->dev;
@@ -1216,17 +1216,11 @@ static int __saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *a
 #endif
        default:
                return v4l_compat_translate_ioctl(file, cmd, arg,
-                                                 __saa7146_video_do_ioctl);
+                                                 saa7146_video_do_ioctl);
        }
        return 0;
 }
 
-int saa7146_video_do_ioctl(struct inode *inode, struct file *file,
-                                   unsigned int cmd, void *arg)
-{
-       return __saa7146_video_do_ioctl(file, cmd, arg);
-}
-
 /*********************************************************************************/
 /* buffer handling functions                                                  */
 
index a8878244bb3c40432fe6b3420e32e338ae32f0ad..31522d2e318ea23dbb9ca41c4fcba4b2e7141abf 100644 (file)
@@ -3598,7 +3598,7 @@ static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
                76, 77, 91, 134, 135, 137, 147,
                156, 166, 167, 168, 25 };
 
-       *count = sizeof(RegAddr) / sizeof(u8);
+       *count = ARRAY_SIZE(RegAddr);
 
        status += MXL_BlockInit(fe);
 
@@ -3630,7 +3630,7 @@ static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal,
        */
 #endif
 
-       *count = sizeof(RegAddr) / sizeof(u8);
+       *count = ARRAY_SIZE(RegAddr);
 
        for (i = 0 ; i < *count; i++) {
                RegNum[i] = RegAddr[i];
@@ -3648,7 +3648,7 @@ static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
 
        u8 RegAddr[] = {43, 136};
 
-       *count = sizeof(RegAddr) / sizeof(u8);
+       *count = ARRAY_SIZE(RegAddr);
 
        for (i = 0; i < *count; i++) {
                RegNum[i] = RegAddr[i];
index 4a74f65e759aad5bc622ed7178cd13f1e2416f0c..f4d931f14fad5bae30b8fc73e94aeec3e9891199 100644 (file)
@@ -80,10 +80,11 @@ static void tda827x_set_std(struct dvb_frontend *fe,
                mode = "xx";
        }
 
-       if (params->mode == V4L2_TUNER_RADIO)
+       if (params->mode == V4L2_TUNER_RADIO) {
                priv->sgIF = 88; /* if frequency is 5.5 MHz */
-
-       dprintk("setting tda827x to system %s\n", mode);
+               dprintk("setting tda827x to radio FM\n");
+       } else
+               dprintk("setting tda827x to system %s\n", mode);
 }
 
 
@@ -199,7 +200,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
                fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(priv->i2c_adap, &msg, 1);
 
-       priv->frequency = tuner_freq - if_freq; // FIXME
+       priv->frequency = params->frequency;
        priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
        return 0;
@@ -304,7 +305,7 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe,
        reg2[1] = 0x08;   /* Vsync en */
        i2c_transfer(priv->i2c_adap, &msg, 1);
 
-       priv->frequency = freq * 62500;
+       priv->frequency = params->frequency;
 
        return 0;
 }
@@ -591,7 +592,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
                fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(priv->i2c_adap, &msg, 1);
 
-       priv->frequency = tuner_freq - if_freq; // FIXME
+       priv->frequency = params->frequency;
        priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
        return 0;
@@ -691,7 +692,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
        tuner_reg[1] = 0x19 + (priv->lpsel << 1);
        i2c_transfer(priv->i2c_adap, &msg, 1);
 
-       priv->frequency = freq * 62500;
+       priv->frequency = params->frequency;
 
        return 0;
 }
index c112bdd4e0f04a89a7ffe60fdaa143e6721339f8..0ee79fd7c7a95825b8903a21bc23ff01589d0652 100644 (file)
@@ -32,6 +32,9 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
+static int deemphasis_50;
+MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
+
 /* ---------------------------------------------------------------------- */
 
 struct tda8290_priv {
@@ -139,9 +142,34 @@ static void set_audio(struct dvb_frontend *fe,
                mode = "xx";
        }
 
-       tuner_dbg("setting tda829x to system %s\n", mode);
+       if (params->mode == V4L2_TUNER_RADIO) {
+               priv->tda8290_easy_mode = 0x01;         /* Start with MN values */
+               tuner_dbg("setting to radio FM\n");
+       } else {
+               tuner_dbg("setting tda829x to system %s\n", mode);
+       }
 }
 
+struct {
+       unsigned char seq[2];
+} fm_mode[] = {
+       { { 0x01, 0x81} },      /* Put device into expert mode */
+       { { 0x03, 0x48} },      /* Disable NOTCH and VIDEO filters */
+       { { 0x04, 0x04} },      /* Disable color carrier filter (SSIF) */
+       { { 0x05, 0x04} },      /* ADC headroom */
+       { { 0x06, 0x10} },      /* group delay flat */
+
+       { { 0x07, 0x00} },      /* use the same radio DTO values as a tda8295 */
+       { { 0x08, 0x00} },
+       { { 0x09, 0x80} },
+       { { 0x0a, 0xda} },
+       { { 0x0b, 0x4b} },
+       { { 0x0c, 0x68} },
+
+       { { 0x0d, 0x00} },      /* PLL off, no video carrier detect */
+       { { 0x14, 0x00} },      /* disable auto mute if no video */
+};
+
 static void tda8290_set_params(struct dvb_frontend *fe,
                               struct analog_parameters *params)
 {
@@ -178,15 +206,30 @@ static void tda8290_set_params(struct dvb_frontend *fe,
        tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
        msleep(1);
 
-       expert_mode[1] = priv->tda8290_easy_mode + 0x80;
-       tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
-       tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
-       tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
-       if (priv->tda8290_easy_mode & 0x60)
-               tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
-       else
-               tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
-       tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+       if (params->mode == V4L2_TUNER_RADIO) {
+               int i;
+               unsigned char deemphasis[]  = { 0x13, 1 };
+
+               /* FIXME: allow using a different deemphasis */
+
+               if (deemphasis_50)
+                       deemphasis[1] = 2;
+
+               for (i = 0; i < ARRAY_SIZE(fm_mode); i++)
+                       tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2);
+
+               tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2);
+       } else {
+               expert_mode[1] = priv->tda8290_easy_mode + 0x80;
+               tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
+               tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
+               tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
+               if (priv->tda8290_easy_mode & 0x60)
+                       tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
+               else
+                       tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
+               tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+       }
 
        tda8290_i2c_bridge(fe, 1);
 
index ff1788cc5d48ef6068a9759dd61061388e299445..544cdbe88a6c9220eef89326ee363739cb0f2434 100644 (file)
@@ -180,11 +180,10 @@ static struct tvnorm tvnorms[] = {
        },{
                .std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
                .name  = "SECAM-BGH",
-               .b     = ( cPositiveAmTV  |
+               .b     = ( cNegativeFmTV  |
                           cQSS           ),
                .c     = ( cTopDefault),
-               .e     = ( cGating_36     |
-                          cAudioIF_5_5   |
+               .e     = ( cAudioIF_5_5   |
                           cVideoIF_38_90 ),
        },{
                .std   = V4L2_STD_SECAM_L,
index b65e6803e6c64983d07f4d6c7a00d1e2fefbb96e..1adce9ff52ce0fea7daee80fa46f94e15f85d1b4 100644 (file)
@@ -28,6 +28,12 @@ static int debug;
 module_param(debug, int, 0644);
 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"
+       "1 keep device energized and with tuner ready all the times.\n"
+       "  Faster, but consumes more power and keeps the device hotter\n");
+
 static char audio_std[8];
 module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
 MODULE_PARM_DESC(audio_std,
@@ -1091,6 +1097,34 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                                T_DIGITAL_TV, type, 0, demod);
 }
 
+static int xc2028_sleep(struct dvb_frontend *fe)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int rc = 0;
+
+       /* Avoid firmware reload on slow devices */
+       if (no_poweroff)
+               return 0;
+
+       tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
+       if (debug > 1) {
+               tuner_dbg("Printing sleep stack trace:\n");
+               dump_stack();
+       }
+
+       mutex_lock(&priv->lock);
+
+       if (priv->firm_version < 0x0202)
+               rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
+       else
+               rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
+
+       priv->cur_fw.type = 0;  /* need firmware reload */
+
+       mutex_unlock(&priv->lock);
+
+       return rc;
+}
 
 static int xc2028_dvb_release(struct dvb_frontend *fe)
 {
@@ -1171,6 +1205,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
        .get_frequency     = xc2028_get_frequency,
        .get_rf_strength   = xc2028_signal,
        .set_params        = xc2028_set_params,
+       .sleep             = xc2028_sleep,
 };
 
 struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
index e12d13e0cbe9744b790c3b1089ac485aced7a2a8..493ce93caf43538a2580854ab150648cf7dfb059 100644 (file)
@@ -36,10 +36,6 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
-static int xc5000_load_fw_on_attach;
-module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
-MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
-
 static DEFINE_MUTEX(xc5000_list_mutex);
 static LIST_HEAD(hybrid_tuner_instance_list);
 
@@ -1017,9 +1013,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
        memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
                sizeof(struct dvb_tuner_ops));
 
-       if (xc5000_load_fw_on_attach)
-               xc5000_init(fe);
-
        return fe;
 fail:
        mutex_unlock(&xc5000_list_mutex);
index 0bcd852576d686a2b556b05e72467d687d49181d..40ebde53b3ce22443a60be62357c5722f64f256d 100644 (file)
@@ -2,6 +2,19 @@
 # DVB device configuration
 #
 
+config DVB_DYNAMIC_MINORS
+       bool "Dynamic DVB minor allocation"
+       depends on DVB_CORE
+       default n
+       help
+         If you say Y here, the DVB subsystem will use dynamic minor
+         allocation for any device that uses the DVB major number.
+         This means that you can have more than 4 of a single type
+         of device (like demuxes and frontends) per adapter, but udev
+         will be required to manage the device nodes.
+
+         If you are unsure about this, say N here.
+
 menuconfig DVB_CAPTURE_DRIVERS
        bool "DVB/ATSC adapters"
        depends on DVB_CORE
index b34301d56cd2859f7b248ee0df8c7899317d59d5..a8c6249c40999c22e8117f64ba3a967fb33088a7 100644 (file)
@@ -14,6 +14,7 @@ config DVB_B2C2_FLEXCOP
        select DVB_ISL6421 if !DVB_FE_CUSTOMISE
        select DVB_CX24123 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+       select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
        help
          Support for the digital TV receiver chip made by B2C2 Inc. included in
          Technisats PCI cards and USB boxes.
index a21ce9edcc7ee1f383567ed8bc48a0d5d452c143..f48f73aff195ae7d60a918288d15027983a62a8a 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -368,7 +367,7 @@ static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb)
 {
        dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);
 
-       return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr);
+       return !dm1105dvb->ts_buf;
 }
 
 static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
index 7a421e9dba5aeef3e0ee51036dfe327359fbd273..171f9ca124f715d2bc05f3656e1b1892dd08ec1a 100644 (file)
@@ -128,6 +128,7 @@ struct dvb_frontend_private {
        unsigned int step_size;
        int quality;
        unsigned int check_wrapped;
+       enum dvbfe_search algo_status;
 };
 
 static void dvb_frontend_wakeup(struct dvb_frontend *fe);
@@ -516,6 +517,8 @@ static int dvb_frontend_thread(void *data)
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        unsigned long timeout;
        fe_status_t s;
+       enum dvbfe_algo algo;
+
        struct dvb_frontend_parameters *params;
 
        dprintk("%s\n", __func__);
@@ -562,23 +565,80 @@ restart:
 
                /* do an iteration of the tuning loop */
                if (fe->ops.get_frontend_algo) {
-                       if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
-                               /* have we been asked to retune? */
-                               params = NULL;
+                       algo = fe->ops.get_frontend_algo(fe);
+                       switch (algo) {
+                       case DVBFE_ALGO_HW:
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
+                               params = NULL; /* have we been asked to RETUNE ? */
+
                                if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
                                        params = &fepriv->parameters;
                                        fepriv->state = FESTATE_TUNED;
                                }
 
-                               fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
-                               if (s != fepriv->status) {
+                               if (fe->ops.tune)
+                                       fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+
+                               if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
+                                       dprintk("%s: state changed, adding current state\n", __func__);
                                        dvb_frontend_add_event(fe, s);
                                        fepriv->status = s;
                                }
-                       } else
+                               break;
+                       case DVBFE_ALGO_SW:
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
                                dvb_frontend_swzigzag(fe);
-               } else
+                               break;
+                       case DVBFE_ALGO_CUSTOM:
+                               params = NULL; /* have we been asked to RETUNE ?        */
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
+                               if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
+                                       params = &fepriv->parameters;
+                                       fepriv->state = FESTATE_TUNED;
+                               }
+                               /* Case where we are going to search for a carrier
+                                * User asked us to retune again for some reason, possibly
+                                * requesting a search with a new set of parameters
+                                */
+                               if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
+                                       if (fe->ops.search) {
+                                               fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
+                                               /* We did do a search as was requested, the flags are
+                                                * now unset as well and has the flags wrt to search.
+                                                */
+                                       } else {
+                                               fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
+                                       }
+                               }
+                               /* Track the carrier if the search was successful */
+                               if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
+                                       if (fe->ops.track)
+                                               fe->ops.track(fe, &fepriv->parameters);
+                               } else {
+                                       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       fepriv->delay = HZ / 2;
+                               }
+                               fe->ops.read_status(fe, &s);
+                               if (s != fepriv->status) {
+                                       dvb_frontend_add_event(fe, s); /* update event list */
+                                       fepriv->status = s;
+                                       if (!(s & FE_HAS_LOCK)) {
+                                               fepriv->delay = HZ / 10;
+                                               fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       } else {
+                                               fepriv->delay = 60 * HZ;
+                                       }
+                               }
+                               break;
+                       default:
+                               dprintk("%s: UNDEFINED ALGO !\n", __func__);
+                               break;
+                       }
+               } else {
                        dvb_frontend_swzigzag(fe);
+               }
        }
 
        if (dvb_powerdown_on_sleep) {
@@ -1226,6 +1286,9 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
                dprintk("%s() Finalised property cache\n", __func__);
                dtv_property_cache_submit(fe);
 
+               /* Request the search algorithm to search */
+               fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+
                r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
                        &fepriv->parameters);
                break;
index db4a63b0a32e6e30a296e4b2ccae64f826ca8502..e176da472d7a716d69799546270d10e9979732f3 100644 (file)
@@ -69,6 +69,125 @@ struct analog_parameters {
        u64 std;
 };
 
+enum dvbfe_modcod {
+       DVBFE_MODCOD_DUMMY_PLFRAME      = 0,
+       DVBFE_MODCOD_QPSK_1_4,
+       DVBFE_MODCOD_QPSK_1_3,
+       DVBFE_MODCOD_QPSK_2_5,
+       DVBFE_MODCOD_QPSK_1_2,
+       DVBFE_MODCOD_QPSK_3_5,
+       DVBFE_MODCOD_QPSK_2_3,
+       DVBFE_MODCOD_QPSK_3_4,
+       DVBFE_MODCOD_QPSK_4_5,
+       DVBFE_MODCOD_QPSK_5_6,
+       DVBFE_MODCOD_QPSK_8_9,
+       DVBFE_MODCOD_QPSK_9_10,
+       DVBFE_MODCOD_8PSK_3_5,
+       DVBFE_MODCOD_8PSK_2_3,
+       DVBFE_MODCOD_8PSK_3_4,
+       DVBFE_MODCOD_8PSK_5_6,
+       DVBFE_MODCOD_8PSK_8_9,
+       DVBFE_MODCOD_8PSK_9_10,
+       DVBFE_MODCOD_16APSK_2_3,
+       DVBFE_MODCOD_16APSK_3_4,
+       DVBFE_MODCOD_16APSK_4_5,
+       DVBFE_MODCOD_16APSK_5_6,
+       DVBFE_MODCOD_16APSK_8_9,
+       DVBFE_MODCOD_16APSK_9_10,
+       DVBFE_MODCOD_32APSK_3_4,
+       DVBFE_MODCOD_32APSK_4_5,
+       DVBFE_MODCOD_32APSK_5_6,
+       DVBFE_MODCOD_32APSK_8_9,
+       DVBFE_MODCOD_32APSK_9_10,
+       DVBFE_MODCOD_RESERVED_1,
+       DVBFE_MODCOD_BPSK_1_3,
+       DVBFE_MODCOD_BPSK_1_4,
+       DVBFE_MODCOD_RESERVED_2
+};
+
+enum tuner_param {
+       DVBFE_TUNER_FREQUENCY           = (1 <<  0),
+       DVBFE_TUNER_TUNERSTEP           = (1 <<  1),
+       DVBFE_TUNER_IFFREQ              = (1 <<  2),
+       DVBFE_TUNER_BANDWIDTH           = (1 <<  3),
+       DVBFE_TUNER_REFCLOCK            = (1 <<  4),
+       DVBFE_TUNER_IQSENSE             = (1 <<  5),
+       DVBFE_TUNER_DUMMY               = (1 << 31)
+};
+
+/*
+ * ALGO_HW: (Hardware Algorithm)
+ * ----------------------------------------------------------------
+ * Devices that support this algorithm do everything in hardware
+ * and no software support is needed to handle them.
+ * Requesting these devices to LOCK is the only thing required,
+ * device is supposed to do everything in the hardware.
+ *
+ * ALGO_SW: (Software Algorithm)
+ * ----------------------------------------------------------------
+ * These are dumb devices, that require software to do everything
+ *
+ * ALGO_CUSTOM: (Customizable Agorithm)
+ * ----------------------------------------------------------------
+ * Devices having this algorithm can be customized to have specific
+ * algorithms in the frontend driver, rather than simply doing a
+ * software zig-zag. In this case the zigzag maybe hardware assisted
+ * or it maybe completely done in hardware. In all cases, usage of
+ * this algorithm, in conjunction with the search and track
+ * callbacks, utilizes the driver specific algorithm.
+ *
+ * ALGO_RECOVERY: (Recovery Algorithm)
+ * ----------------------------------------------------------------
+ * These devices have AUTO recovery capabilities from LOCK failure
+ */
+enum dvbfe_algo {
+       DVBFE_ALGO_HW                   = (1 <<  0),
+       DVBFE_ALGO_SW                   = (1 <<  1),
+       DVBFE_ALGO_CUSTOM               = (1 <<  2),
+       DVBFE_ALGO_RECOVERY             = (1 << 31)
+};
+
+struct tuner_state {
+       u32 frequency;
+       u32 tunerstep;
+       u32 ifreq;
+       u32 bandwidth;
+       u32 iqsense;
+       u32 refclock;
+};
+
+/*
+ * search callback possible return status
+ *
+ * DVBFE_ALGO_SEARCH_SUCCESS
+ * The frontend search algorithm completed and returned succesfully
+ *
+ * DVBFE_ALGO_SEARCH_ASLEEP
+ * The frontend search algorithm is sleeping
+ *
+ * DVBFE_ALGO_SEARCH_FAILED
+ * The frontend search for a signal failed
+ *
+ * DVBFE_ALGO_SEARCH_INVALID
+ * The frontend search algorith was probably supplied with invalid
+ * parameters and the search is an invalid one
+ *
+ * DVBFE_ALGO_SEARCH_ERROR
+ * The frontend search algorithm failed due to some error
+ *
+ * DVBFE_ALGO_SEARCH_AGAIN
+ * The frontend search algorithm was requested to search again
+ */
+enum dvbfe_search {
+       DVBFE_ALGO_SEARCH_SUCCESS       = (1 <<  0),
+       DVBFE_ALGO_SEARCH_ASLEEP        = (1 <<  1),
+       DVBFE_ALGO_SEARCH_FAILED        = (1 <<  2),
+       DVBFE_ALGO_SEARCH_INVALID       = (1 <<  3),
+       DVBFE_ALGO_SEARCH_AGAIN         = (1 <<  4),
+       DVBFE_ALGO_SEARCH_ERROR         = (1 << 31),
+};
+
+
 struct dvb_tuner_ops {
 
        struct dvb_tuner_info info;
@@ -99,6 +218,13 @@ struct dvb_tuner_ops {
         * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
        int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
        int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+
+       /*
+        * These are provided seperately from set_params in order to facilitate silicon
+        * tuners which require sophisticated tuning loops, controlling each parameter seperately.
+        */
+       int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+       int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
 };
 
 struct analog_demod_info {
@@ -142,7 +268,7 @@ struct dvb_frontend_ops {
                    unsigned int *delay,
                    fe_status_t *status);
        /* get frontend tuning algorithm from the module */
-       int (*get_frontend_algo)(struct dvb_frontend *fe);
+       enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
 
        /* these two are only used for the swzigzag code */
        int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
@@ -167,6 +293,12 @@ struct dvb_frontend_ops {
        int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
        int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
 
+       /* These callbacks are for devices that implement their own
+        * tuning algorithms, rather than a simple swzigzag
+        */
+       enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+       int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+
        struct dvb_tuner_ops tuner_ops;
        struct analog_demod_ops analog_ops;
 
index a113744a56cc136c0355184b0af4504b0219970a..6c571d9f011c6df050c23230c399390e5c3e7334 100644 (file)
@@ -50,33 +50,27 @@ static const char * const dnames[] = {
        "net", "osd"
 };
 
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+#define MAX_DVB_MINORS         256
+#define DVB_MAX_IDS            MAX_DVB_MINORS
+#else
 #define DVB_MAX_IDS            4
 #define nums2minor(num,type,id)        ((num << 6) | (id << 4) | type)
 #define MAX_DVB_MINORS         (DVB_MAX_ADAPTERS*64)
+#endif
 
 static struct class *dvb_class;
 
-static struct dvb_device* dvbdev_find_device (int minor)
-{
-       struct dvb_adapter *adap;
-
-       list_for_each_entry(adap, &dvb_adapter_list, list_head) {
-               struct dvb_device *dev;
-               list_for_each_entry(dev, &adap->device_list, list_head)
-                       if (nums2minor(adap->num, dev->type, dev->id) == minor)
-                               return dev;
-       }
-
-       return NULL;
-}
-
+static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
+static DECLARE_RWSEM(minor_rwsem);
 
 static int dvb_device_open(struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev;
 
        lock_kernel();
-       dvbdev = dvbdev_find_device (iminor(inode));
+       down_read(&minor_rwsem);
+       dvbdev = dvb_minors[iminor(inode)];
 
        if (dvbdev && dvbdev->fops) {
                int err = 0;
@@ -92,9 +86,11 @@ static int dvb_device_open(struct inode *inode, struct file *file)
                        file->f_op = fops_get(old_fops);
                }
                fops_put(old_fops);
+               up_read(&minor_rwsem);
                unlock_kernel();
                return err;
        }
+       up_read(&minor_rwsem);
        unlock_kernel();
        return -ENODEV;
 }
@@ -192,6 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        struct dvb_device *dvbdev;
        struct file_operations *dvbdevfops;
        struct device *clsdev;
+       int minor;
        int id;
 
        mutex_lock(&dvbdev_register_lock);
@@ -231,11 +228,31 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 
        list_add_tail (&dvbdev->list_head, &adap->device_list);
 
+       down_write(&minor_rwsem);
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+       for (minor = 0; minor < MAX_DVB_MINORS; minor++)
+               if (dvb_minors[minor] == NULL)
+                       break;
+
+       if (minor == MAX_DVB_MINORS) {
+               kfree(dvbdevfops);
+               kfree(dvbdev);
+               mutex_unlock(&dvbdev_register_lock);
+               return -EINVAL;
+       }
+#else
+       minor = nums2minor(adap->num, type, id);
+#endif
+
+       dvbdev->minor = minor;
+       dvb_minors[minor] = dvbdev;
+       up_write(&minor_rwsem);
+
        mutex_unlock(&dvbdev_register_lock);
 
        clsdev = device_create(dvb_class, adap->device,
-                              MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
-                              NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+                              MKDEV(DVB_MAJOR, minor),
+                              dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
        if (IS_ERR(clsdev)) {
                printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
                       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
@@ -243,8 +260,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        }
 
        dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
-               adap->num, dnames[type], id, nums2minor(adap->num, type, id),
-               nums2minor(adap->num, type, id));
+               adap->num, dnames[type], id, minor, minor);
 
        return 0;
 }
@@ -256,8 +272,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
        if (!dvbdev)
                return;
 
-       device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
-                      dvbdev->type, dvbdev->id)));
+       down_write(&minor_rwsem);
+       dvb_minors[dvbdev->minor] = NULL;
+       up_write(&minor_rwsem);
+
+       device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
 
        list_del (&dvbdev->list_head);
        kfree (dvbdev->fops);
@@ -413,6 +432,15 @@ out:
        return err;
 }
 
+static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+       add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
+       add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
+       return 0;
+}
+
 static int __init init_dvbdev(void)
 {
        int retval;
@@ -434,6 +462,7 @@ static int __init init_dvbdev(void)
                retval = PTR_ERR(dvb_class);
                goto error;
        }
+       dvb_class->dev_uevent = dvb_uevent;
        return 0;
 
 error:
index 574e336bac35b7b8d81471a32fea7c2558fc530c..dca49cf962e864c37cefad089669187735f8c524 100644 (file)
@@ -74,6 +74,7 @@ struct dvb_device {
        struct file_operations *fops;
        struct dvb_adapter *adapter;
        int type;
+       int minor;
        u32 id;
 
        /* in theory, 'users' can vanish now,
index e9ab0249d13305435715bc5b4b7c03d9d9aef888..e1e9aa5c6b843991c13ba4286ed92d650b728e97 100644 (file)
@@ -733,9 +733,19 @@ static int af9015_read_config(struct usb_device *udev)
                                af9015_config.ir_table_size =
                                  ARRAY_SIZE(af9015_ir_table_mygictv);
                                break;
+                       case AF9015_REMOTE_DIGITTRADE_DVB_T:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_digittrade;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_digittrade);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_digittrade;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_digittrade);
+                               break;
                        }
                } else {
-                       switch (udev->descriptor.idVendor) {
+                       switch (le16_to_cpu(udev->descriptor.idVendor)) {
                        case USB_VID_LEADTEK:
                                af9015_properties[i].rc_key_map =
                                  af9015_rc_keys_leadtek;
@@ -748,7 +758,7 @@ static int af9015_read_config(struct usb_device *udev)
                                break;
                        case USB_VID_VISIONPLUS:
                                if (udev->descriptor.idProduct ==
-                               USB_PID_AZUREWAVE_AD_TU700) {
+                               cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) {
                                        af9015_properties[i].rc_key_map =
                                          af9015_rc_keys_twinhan;
                                        af9015_properties[i].rc_key_map_size =
@@ -800,6 +810,16 @@ static int af9015_read_config(struct usb_device *udev)
                                          ARRAY_SIZE(af9015_ir_table_msi);
                                }
                                break;
+                       case USB_VID_AVERMEDIA:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_avermedia;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_avermedia);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_avermedia;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_avermedia);
+                               break;
                        }
                }
        }
@@ -1191,6 +1211,7 @@ static struct usb_device_id af9015_usb_table[] = {
        {USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2)},
        {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
 /* 15 */{USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGI_VOX_MINI_III)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1343,7 +1364,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 6,
+               .num_device_descs = 7,
                .devices = {
                        {
                                .name = "Xtensions XD-380",
@@ -1375,6 +1396,12 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                .cold_ids = {&af9015_usb_table[15], NULL},
                                .warm_ids = {NULL},
                        },
+                       {
+                               .name = "KWorld USB DVB-T TV Stick II " \
+                                       "(VS-DVB-T 395U)",
+                               .cold_ids = {&af9015_usb_table[16], NULL},
+                               .warm_ids = {NULL},
+                       },
                }
        }
 };
index 6c3c97293316b29c2606eb29837b8b1c789a381c..21c7782f4889c32121d6ac1b3d668319d9e3d961 100644 (file)
@@ -123,6 +123,7 @@ enum af9015_remote {
        AF9015_REMOTE_A_LINK_DTU_M,
        AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
        AF9015_REMOTE_MYGICTV_U718,
+       AF9015_REMOTE_DIGITTRADE_DVB_T,
 };
 
 /* Leadtek WinFast DTV Dongle Gold */
@@ -520,4 +521,143 @@ static u8 af9015_ir_table_kworld[] = {
        0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
 };
 
+/* AverMedia Volar X */
+static struct dvb_usb_rc_key af9015_rc_keys_avermedia[] = {
+       { 0x05, 0x3d, KEY_PROG1 },       /* SOURCE */
+       { 0x05, 0x12, KEY_POWER },       /* POWER */
+       { 0x05, 0x1e, KEY_1 },           /* 1 */
+       { 0x05, 0x1f, KEY_2 },           /* 2 */
+       { 0x05, 0x20, KEY_3 },           /* 3 */
+       { 0x05, 0x21, KEY_4 },           /* 4 */
+       { 0x05, 0x22, KEY_5 },           /* 5 */
+       { 0x05, 0x23, KEY_6 },           /* 6 */
+       { 0x05, 0x24, KEY_7 },           /* 7 */
+       { 0x05, 0x25, KEY_8 },           /* 8 */
+       { 0x05, 0x26, KEY_9 },           /* 9 */
+       { 0x05, 0x3f, KEY_LEFT },        /* L / DISPLAY */
+       { 0x05, 0x27, KEY_0 },           /* 0 */
+       { 0x05, 0x0f, KEY_RIGHT },       /* R / CH RTN */
+       { 0x05, 0x18, KEY_PROG2 },       /* SNAP SHOT */
+       { 0x05, 0x1c, KEY_PROG3 },       /* 16-CH PREV */
+       { 0x05, 0x2d, KEY_VOLUMEDOWN },  /* VOL DOWN */
+       { 0x05, 0x3e, KEY_ZOOM },        /* FULL SCREEN */
+       { 0x05, 0x2e, KEY_VOLUMEUP },    /* VOL UP */
+       { 0x05, 0x10, KEY_MUTE },        /* MUTE */
+       { 0x05, 0x04, KEY_AUDIO },       /* AUDIO */
+       { 0x05, 0x15, KEY_RECORD },      /* RECORD */
+       { 0x05, 0x11, KEY_PLAY },        /* PLAY */
+       { 0x05, 0x16, KEY_STOP },        /* STOP */
+       { 0x05, 0x0c, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
+       { 0x05, 0x05, KEY_BACK },        /* << / RED */
+       { 0x05, 0x09, KEY_FORWARD },     /* >> / YELLOW */
+       { 0x05, 0x17, KEY_TEXT },        /* TELETEXT */
+       { 0x05, 0x0a, KEY_EPG },         /* EPG */
+       { 0x05, 0x13, KEY_MENU },        /* MENU */
+
+       { 0x05, 0x0e, KEY_CHANNELUP },   /* CH UP */
+       { 0x05, 0x0d, KEY_CHANNELDOWN }, /* CH DOWN */
+       { 0x05, 0x19, KEY_FIRST },       /* |<< / GREEN */
+       { 0x05, 0x08, KEY_LAST },        /* >>| / BLUE */
+};
+
+static u8 af9015_ir_table_avermedia[] = {
+       0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00,
+       0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00,
+       0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00,
+       0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00,
+       0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00,
+       0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00,
+       0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00,
+       0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00,
+       0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00,
+       0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00,
+       0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00,
+       0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00,
+       0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00,
+       0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00,
+       0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00,
+       0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00,
+       0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00,
+       0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00,
+       0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00,
+       0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00,
+       0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00,
+       0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00,
+       0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00,
+       0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00,
+       0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00,
+       0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00,
+       0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00,
+       0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00,
+       0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00,
+       0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00,
+       0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00,
+       0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00,
+       0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00,
+       0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
+};
+
+/* Digittrade DVB-T USB Stick */
+static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = {
+       { 0x01, 0x0f, KEY_LAST },       /* RETURN */
+       { 0x05, 0x17, KEY_TEXT },       /* TELETEXT */
+       { 0x01, 0x08, KEY_EPG },        /* EPG */
+       { 0x05, 0x13, KEY_POWER },      /* POWER */
+       { 0x01, 0x09, KEY_ZOOM },       /* FULLSCREEN */
+       { 0x00, 0x40, KEY_AUDIO },      /* DUAL SOUND */
+       { 0x00, 0x2c, KEY_PRINT },      /* SNAPSHOT */
+       { 0x05, 0x16, KEY_SUBTITLE },   /* SUBTITLE */
+       { 0x00, 0x52, KEY_CHANNELUP },  /* CH Up */
+       { 0x00, 0x51, KEY_CHANNELDOWN },/* Ch Dn */
+       { 0x00, 0x57, KEY_VOLUMEUP },   /* Vol Up */
+       { 0x00, 0x56, KEY_VOLUMEDOWN }, /* Vol Dn */
+       { 0x01, 0x10, KEY_MUTE },       /* MUTE */
+       { 0x00, 0x27, KEY_0 },
+       { 0x00, 0x1e, KEY_1 },
+       { 0x00, 0x1f, KEY_2 },
+       { 0x00, 0x20, KEY_3 },
+       { 0x00, 0x21, KEY_4 },
+       { 0x00, 0x22, KEY_5 },
+       { 0x00, 0x23, KEY_6 },
+       { 0x00, 0x24, KEY_7 },
+       { 0x00, 0x25, KEY_8 },
+       { 0x00, 0x26, KEY_9 },
+       { 0x01, 0x17, KEY_PLAYPAUSE },  /* TIMESHIFT */
+       { 0x01, 0x15, KEY_RECORD },     /* RECORD */
+       { 0x03, 0x13, KEY_PLAY },       /* PLAY */
+       { 0x01, 0x16, KEY_STOP },       /* STOP */
+       { 0x01, 0x13, KEY_PAUSE },      /* PAUSE */
+};
+
+static u8 af9015_ir_table_digittrade[] = {
+       0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00,
+       0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00,
+       0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00,
+       0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00,
+       0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00,
+       0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00,
+       0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00,
+       0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00,
+       0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00,
+       0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00,
+       0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00,
+       0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00,
+       0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00,
+       0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00,
+       0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00,
+       0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00,
+       0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00,
+       0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00,
+       0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00,
+       0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00,
+       0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00,
+       0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00,
+       0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00,
+       0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00,
+       0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00,
+       0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00,
+       0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00,
+       0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
+};
+
 #endif
index cd2edbcaa09755e0c3d7e76b585f346731114983..5017f08b14a6a2de96771727cc9c254cad0d8e4e 100644 (file)
@@ -153,7 +153,7 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
        int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
-       int ret, inc, i = 0;
+       int ret = 0, inc, i = 0;
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
index 3ac9f74e9fbf30c1207e4aa34b6bf604e9fb7cc6..80e37a0d0892298c167356d5a0b1b2158c518f6a 100644 (file)
@@ -32,7 +32,6 @@
 
 /* debug */
 int dvb_usb_cinergyt2_debug;
-int disable_remote;
 
 module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
@@ -45,7 +44,7 @@ struct cinergyt2_state {
 };
 
 /* We are missing a release hook with usb_device data */
-struct dvb_usb_device *cinergyt2_usb_device;
+static struct dvb_usb_device *cinergyt2_usb_device;
 
 static struct dvb_usb_device_properties cinergyt2_properties;
 
index 11d79eb384c882c23556ae69e1005ed29ef2d10a..84efe03771eb1da8278cf613fd051f2b58f17b35 100644 (file)
@@ -70,11 +70,11 @@ struct dvbt_get_status_msg {
        uint8_t bandwidth;
        uint16_t tps;
        uint8_t flags;
-       uint16_t gain;
+       __le16 gain;
        uint8_t snr;
-       uint32_t viterbi_error_rate;
+       __le32 viterbi_error_rate;
        uint32_t rs_error_rate;
-       uint32_t uncorrected_block_count;
+       __le32 uncorrected_block_count;
        uint8_t lock_bits;
        uint8_t prev_lock_bits;
 } __attribute__((packed));
@@ -82,9 +82,9 @@ struct dvbt_get_status_msg {
 
 struct dvbt_set_parameters_msg {
        uint8_t cmd;
-       uint32_t freq;
+       __le32 freq;
        uint8_t bandwidth;
-       uint16_t tps;
+       __le16 tps;
        uint8_t flags;
 } __attribute__((packed));
 
index 7380b94b3b36065af00051e7f5f965fb18f3afc1..a4fca3fca5eede1e7c1c4913a7905d72738b804b 100644 (file)
@@ -96,6 +96,7 @@
 #define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
 #define USB_PID_KWORLD_399U                            0xe399
+#define USB_PID_KWORLD_395U                            0xe396
 #define USB_PID_KWORLD_PC160_2T                                0xc160
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
index 6286fbbe7fb5bd1178065d5618c817ab2da5a45d..c65f273ff313cda9d874f3183f343949da953169 100644 (file)
@@ -9,7 +9,6 @@
 *
 * see Documentation/dvb/README.dvb-usb for more information
 */
-#include <linux/version.h>
 #include "dw2102.h"
 #include "si21xx.h"
 #include "stv0299.h"
 #define USB_PID_DW2104 0x2104
 #endif
 
+#ifndef USB_PID_CINERGY_S
+#define USB_PID_CINERGY_S 0x0064
+#endif
+
 #define DW210X_READ_MSG 0
 #define DW210X_WRITE_MSG 1
 
@@ -578,6 +581,7 @@ static struct usb_device_id dw2102_table[] = {
        {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
        {USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
        {USB_DEVICE(0x9022, 0xd650)},
+       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
        { }
 };
 
@@ -647,6 +651,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                        dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
                                        DW210X_WRITE_MSG);
                        break;
+               case USB_PID_CINERGY_S:
                case USB_PID_DW2102:
                        dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
                                        DW210X_WRITE_MSG);
@@ -655,7 +660,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                        /* check STV0299 frontend  */
                        dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
                                        DW210X_READ_MSG);
-                       if (reset16[0] == 0xa1) {
+                       if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
                                dw2102_properties.i2c_algo = &dw2102_i2c_algo;
                                dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
                                break;
@@ -726,7 +731,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
                        },
                }
        },
-       .num_device_descs = 2,
+       .num_device_descs = 3,
        .devices = {
                {"DVBWorld DVB-S 2102 USB2.0",
                        {&dw2102_table[0], NULL},
@@ -736,6 +741,10 @@ static struct dvb_usb_device_properties dw2102_properties = {
                        {&dw2102_table[1], NULL},
                        {NULL},
                },
+               {"TerraTec Cinergy S USB",
+                       {&dw2102_table[4], NULL},
+                       {NULL},
+               },
        }
 };
 
index 262a858c30684e28e0798034e776ed9138f3f255..20eadf9318e08eca422c11f68ab96d4b2557a0c6 100644 (file)
@@ -25,6 +25,20 @@ struct gp8psk_fe_state {
        unsigned long status_check_interval;
 };
 
+static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
+{
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
+       u8 status;
+       gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
+       return status & bmDCtuned;
+}
+
+static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
+{
+       struct gp8psk_fe_state *state = fe->demodulator_priv;
+       return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
+}
+
 static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
 {
        u8 buf[6];
@@ -99,39 +113,114 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
        return 0;
 }
 
+static int gp8psk_fe_set_property(struct dvb_frontend *fe,
+       struct dtv_property *tvp)
+{
+       deb_fe("%s(..)\n", __func__);
+       return 0;
+}
+
+static int gp8psk_fe_get_property(struct dvb_frontend *fe,
+       struct dtv_property *tvp)
+{
+       deb_fe("%s(..)\n", __func__);
+       return 0;
+}
+
+
 static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
                                  struct dvb_frontend_parameters *fep)
 {
        struct gp8psk_fe_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u8 cmd[10];
        u32 freq = fep->frequency * 1000;
+       int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
+
+       deb_fe("%s()\n", __func__);
 
        cmd[4] = freq         & 0xff;
        cmd[5] = (freq >> 8)  & 0xff;
        cmd[6] = (freq >> 16) & 0xff;
        cmd[7] = (freq >> 24) & 0xff;
 
-       switch(fe->ops.info.type) {
-       case FE_QPSK:
-               cmd[0] =  fep->u.qpsk.symbol_rate        & 0xff;
-               cmd[1] = (fep->u.qpsk.symbol_rate >>  8) & 0xff;
-               cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
-               cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
-               cmd[8] = ADV_MOD_DVB_QPSK;
-               cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               /* Only QPSK is supported for DVB-S */
+               if (c->modulation != QPSK) {
+                       deb_fe("%s: unsupported modulation selected (%d)\n",
+                               __func__, c->modulation);
+                       return -EOPNOTSUPP;
+               }
+               c->fec_inner = FEC_AUTO;
                break;
+       case SYS_DVBS2:
+               deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
+               break;
+
        default:
-               // other modes are unsuported right now
-               cmd[0] = 0;
-               cmd[1] = 0;
-               cmd[2] = 0;
-               cmd[3] = 0;
-               cmd[8] = 0;
+               deb_fe("%s: unsupported delivery system selected (%d)\n",
+                       __func__, c->delivery_system);
+               return -EOPNOTSUPP;
+       }
+
+       cmd[0] =  c->symbol_rate        & 0xff;
+       cmd[1] = (c->symbol_rate >>  8) & 0xff;
+       cmd[2] = (c->symbol_rate >> 16) & 0xff;
+       cmd[3] = (c->symbol_rate >> 24) & 0xff;
+       switch (c->modulation) {
+       case QPSK:
+               if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+                       if (gp8psk_tuned_to_DCII(fe))
+                               gp8psk_bcm4500_reload(state->d);
+               switch (c->fec_inner) {
+               case FEC_1_2:
+                       cmd[9] = 0; break;
+               case FEC_2_3:
+                       cmd[9] = 1; break;
+               case FEC_3_4:
+                       cmd[9] = 2; break;
+               case FEC_5_6:
+                       cmd[9] = 3; break;
+               case FEC_7_8:
+                       cmd[9] = 4; break;
+               case FEC_AUTO:
+                       cmd[9] = 5; break;
+               default:
+                       cmd[9] = 5; break;
+               }
+               cmd[8] = ADV_MOD_DVB_QPSK;
+               break;
+       case PSK_8: /* PSK_8 is for compatibility with DN */
+               cmd[8] = ADV_MOD_TURBO_8PSK;
+               switch (c->fec_inner) {
+               case FEC_2_3:
+                       cmd[9] = 0; break;
+               case FEC_3_4:
+                       cmd[9] = 1; break;
+               case FEC_3_5:
+                       cmd[9] = 2; break;
+               case FEC_5_6:
+                       cmd[9] = 3; break;
+               case FEC_8_9:
+                       cmd[9] = 4; break;
+               default:
+                       cmd[9] = 0; break;
+               }
+               break;
+       case QAM_16: /* QAM_16 is for compatibility with DN */
+               cmd[8] = ADV_MOD_TURBO_16QAM;
                cmd[9] = 0;
                break;
+       default: /* Unknown modulation */
+               deb_fe("%s: unsupported modulation selected (%d)\n",
+                       __func__, c->modulation);
+               return -EOPNOTSUPP;
        }
 
-       gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+       if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+               gp8psk_set_tuner_mode(fe, 0);
+       gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
 
        state->lock = 0;
        state->next_status_check = jiffies;
@@ -140,13 +229,6 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
-static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
-{
-       return 0;
-}
-
-
 static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
                                    struct dvb_diseqc_master_cmd *m)
 {
@@ -261,9 +343,13 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
                .symbol_rate_max        = 45000000,
                .symbol_rate_tolerance  = 500,  /* ppm */
                .caps = FE_CAN_INVERSION_AUTO |
-                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-                               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-                               FE_CAN_QPSK
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       /*
+                        * FE_CAN_QAM_16 is for compatibility
+                        * (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
+                        */
+                       FE_CAN_QPSK | FE_CAN_QAM_16
        },
 
        .release = gp8psk_fe_release,
@@ -271,8 +357,10 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
        .init = NULL,
        .sleep = NULL,
 
+       .set_property = gp8psk_fe_set_property,
+       .get_property = gp8psk_fe_get_property,
        .set_frontend = gp8psk_fe_set_frontend,
-       .get_frontend = gp8psk_fe_get_frontend,
+
        .get_tune_settings = gp8psk_fe_get_tune_settings,
 
        .read_status = gp8psk_fe_read_status,
index d965a923f3914e626d3f1cfe35a417ceb417b5dd..c1da962cc8863261fa5a833c72451055b79b4c6b 100644 (file)
@@ -174,6 +174,22 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
        return 0;
 }
 
+int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
+{
+       u8 buf;
+       int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+       /* Turn off 8psk power */
+       if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+               return -EINVAL;
+       /* Turn On 8psk power */
+       if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+               return -EINVAL;
+       /* load BCM4500 firmware */
+       if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+               if (gp8psk_load_bcm4500fw(d))
+                       return EINVAL;
+       return 0;
+}
 
 static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
index e5cd8149c23dc3ea37bf6dcc5d2cea82ea97962e..e83a57506cfa945b2f97d16fb8fc9808221f981d 100644 (file)
@@ -92,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
 extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
 extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
                             u16 index, u8 *b, int blen);
+extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
 
 #endif
index da93b9e982c04e3c67dbc0db671d43ca313a41ee..9da2cc95ca133990115ffeaab2a4f89f931e95a3 100644 (file)
@@ -156,7 +156,8 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream)
                                stream->props.u.bulk.buffersize,
                                usb_urb_complete, stream);
 
-               stream->urb_list[i]->transfer_flags = 0;
+               stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
                stream->urbs_initialized++;
        }
        return 0;
index 96b93e21a84bdbb6ddeb9ea2e3635b50ca0da149..00269560793ae7849d6c320efbd7cfb200a89740 100644 (file)
@@ -12,6 +12,25 @@ config DVB_FE_CUSTOMISE
 
          If unsure say N.
 
+comment "Multistandard (satellite) frontends"
+       depends on DVB_CORE
+
+config DVB_STB0899
+       tristate "STB0899 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
+         to support this demodulator based frontends
+
+config DVB_STB6100
+       tristate "STB6100 based tuners"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A Silicon tuner from ST used in conjunction with the STB0899
+         demodulator. Say Y when you want to support this tuner.
+
 comment "DVB-S (satellite) frontends"
        depends on DVB_CORE
 
@@ -78,6 +97,13 @@ config DVB_TDA10086
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_TDA8261
+       tristate "Philips TDA8261 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
 config DVB_VES1X93
        tristate "VLSI VES1893 or VES1993 based"
        depends on DVB_CORE && I2C
@@ -92,6 +118,14 @@ config DVB_TUNER_ITD1000
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_TUNER_CX24113
+       tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
+
 config DVB_TDA826X
        tristate "Philips TDA826X silicon tuner"
        depends on DVB_CORE && I2C
@@ -345,6 +379,14 @@ config DVB_LGDT330X
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
+config DVB_LGDT3304
+       tristate "LG Electronics LGDT3304"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+         to support this frontend.
+
 config DVB_S5H1409
        tristate "Samsung S5H1409 based"
        depends on DVB_CORE && I2C
@@ -369,6 +411,17 @@ config DVB_S5H1411
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
+comment "ISDB-T (terrestrial) frontends"
+       depends on DVB_CORE
+
+config DVB_S921
+       tristate "Sharp S921 tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
+         Say Y when you want to support this frontend.
+
 comment "Digital terrestrial only tuners/PLL"
        depends on DVB_CORE
 
index aba79f4a63a7217475079e694cb9fc4fbb052d34..af7bdf0ad4c79ae7390d8ae7525e5e04c6f7a51f 100644 (file)
@@ -5,8 +5,13 @@
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
 EXTRA_CFLAGS += -Idrivers/media/common/tuners/
 
+s921-objs := s921_module.o s921_core.o
+stb0899-objs = stb0899_drv.o stb0899_algo.o
+
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
+obj-$(CONFIG_DVB_STB0899) += stb0899.o
+obj-$(CONFIG_DVB_STB6100) += stb6100.o
 obj-$(CONFIG_DVB_SP8870) += sp8870.o
 obj-$(CONFIG_DVB_CX22700) += cx22700.o
 obj-$(CONFIG_DVB_CX24110) += cx24110.o
@@ -35,18 +40,21 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
 obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
 obj-$(CONFIG_DVB_ISL6405) += isl6405.o
 obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
+obj-$(CONFIG_DVB_TDA8261) += tda8261.o
 obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
 obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
 obj-$(CONFIG_DVB_AU8522) += au8522.o
 obj-$(CONFIG_DVB_TDA10048) += tda10048.o
+obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
 obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
 obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
@@ -55,3 +63,5 @@ obj-$(CONFIG_DVB_CX24116) += cx24116.o
 obj-$(CONFIG_DVB_SI21XX) += si21xx.o
 obj-$(CONFIG_DVB_STV0288) += stv0288.o
 obj-$(CONFIG_DVB_STB6000) += stb6000.o
+obj-$(CONFIG_DVB_S921) += s921.o
+
index 692b68a9e73bd2f5af1bc465e6298e0dc218c630..b2b50fb4cfd338002102b868e87b0cac1032954a 100644 (file)
@@ -223,12 +223,12 @@ static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
        int ret = 0;
        u8 i = 0;
        u8 buf[24];
-       u32 ns_coeff1_2048nu;
-       u32 ns_coeff1_8191nu;
-       u32 ns_coeff1_8192nu;
-       u32 ns_coeff1_8193nu;
-       u32 ns_coeff2_2k;
-       u32 ns_coeff2_8k;
+       u32 uninitialized_var(ns_coeff1_2048nu);
+       u32 uninitialized_var(ns_coeff1_8191nu);
+       u32 uninitialized_var(ns_coeff1_8192nu);
+       u32 uninitialized_var(ns_coeff1_8193nu);
+       u32 uninitialized_var(ns_coeff2_2k);
+       u32 uninitialized_var(ns_coeff2_8k);
 
        deb_info("%s: adc_clock:%d bw:%d\n", __func__,
                state->config.adc_clock, bw);
@@ -1009,7 +1009,7 @@ static int af9013_update_snr(struct dvb_frontend *fe)
        int ret;
        u8 buf[3], i, len;
        u32 quant = 0;
-       struct snr_table *snr_table;
+       struct snr_table *uninitialized_var(snr_table);
 
        /* check if quantizer ready (for snr) */
        ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]);
diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c
new file mode 100644 (file)
index 0000000..f6e7b03
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ *  Driver for Conexant CX24113/CX24128 Tuner (Satellite)
+ *
+ *  Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  Developed for BBTI / Technisat
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24113.h"
+
+static int debug;
+
+#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
+#define err(args...)  do { printk(KERN_ERR  "CX24113: " args); } while (0)
+
+#define dprintk(args...) \
+       do { \
+               if (debug) { \
+                       printk(KERN_DEBUG "CX24113: %s: ", __func__); \
+                       printk(args); \
+               } \
+       } while (0)
+
+struct cx24113_state {
+       struct i2c_adapter *i2c;
+       const struct cx24113_config *config;
+
+#define REV_CX24113 0x23
+       u8 rev;
+       u8 ver;
+
+       u8 icp_mode:1;
+
+#define ICP_LEVEL1 0
+#define ICP_LEVEL2 1
+#define ICP_LEVEL3 2
+#define ICP_LEVEL4 3
+       u8 icp_man:2;
+       u8 icp_auto_low:2;
+       u8 icp_auto_mlow:2;
+       u8 icp_auto_mhi:2;
+       u8 icp_auto_hi:2;
+       u8 icp_dig;
+
+#define LNA_MIN_GAIN 0
+#define LNA_MID_GAIN 1
+#define LNA_MAX_GAIN 2
+       u8 lna_gain:2;
+
+       u8 acp_on:1;
+
+       u8 vco_mode:2;
+       u8 vco_shift:1;
+#define VCOBANDSEL_6 0x80
+#define VCOBANDSEL_5 0x01
+#define VCOBANDSEL_4 0x02
+#define VCOBANDSEL_3 0x04
+#define VCOBANDSEL_2 0x08
+#define VCOBANDSEL_1 0x10
+       u8 vco_band;
+
+#define VCODIV4 4
+#define VCODIV2 2
+       u8 vcodiv;
+
+       u8 bs_delay:4;
+       u16 bs_freqcnt:13;
+       u16 bs_rdiv;
+       u8 prescaler_mode:1;
+
+       u8 rfvga_bias_ctrl;
+
+       s16 tuner_gain_thres;
+       u8  gain_level;
+
+       u32 frequency;
+
+       u8 refdiv;
+
+       u8 Fwindow_enabled;
+};
+
+static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
+{
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->i2c_addr,
+               .flags = 0, .buf = buf, .len = 2 };
+       int err = i2c_transfer(state->i2c, &msg, 1);
+       if (err != 1) {
+               printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x,"
+                        " data == 0x%02x)\n", __func__, err, reg, data);
+               return err;
+       }
+
+       return 0;
+}
+
+static int cx24113_readreg(struct cx24113_state *state, u8 reg)
+{
+       int ret;
+       u8 b;
+       struct i2c_msg msg[] = {
+               { .addr = state->config->i2c_addr,
+                       .flags = 0, .buf = &reg, .len = 1 },
+               { .addr = state->config->i2c_addr,
+                       .flags = I2C_M_RD, .buf = &b, .len = 1 }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2) {
+               printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
+                       __func__, reg, ret);
+               return ret;
+       }
+
+       return b;
+}
+
+static void cx24113_set_parameters(struct cx24113_state *state)
+{
+       u8 r;
+
+       r = cx24113_readreg(state, 0x10) & 0x82;
+       r |= state->icp_mode;
+       r |= state->icp_man << 4;
+       r |= state->icp_dig << 2;
+       r |= state->prescaler_mode << 5;
+       cx24113_writereg(state, 0x10, r);
+
+       r = (state->icp_auto_low  << 0) | (state->icp_auto_mlow << 2)
+               | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
+       cx24113_writereg(state, 0x11, r);
+
+       if (state->rev == REV_CX24113) {
+               r = cx24113_readreg(state, 0x20) & 0xec;
+               r |= state->lna_gain;
+               r |= state->rfvga_bias_ctrl << 4;
+               cx24113_writereg(state, 0x20, r);
+       }
+
+       r = cx24113_readreg(state, 0x12) & 0x03;
+       r |= state->acp_on << 2;
+       r |= state->bs_delay << 4;
+       cx24113_writereg(state, 0x12, r);
+
+       r = cx24113_readreg(state, 0x18) & 0x40;
+       r |= state->vco_shift;
+       if (state->vco_band == VCOBANDSEL_6)
+               r |= (1 << 7);
+       else
+               r |= (state->vco_band << 1);
+       cx24113_writereg(state, 0x18, r);
+
+       r  = cx24113_readreg(state, 0x14) & 0x20;
+       r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
+       cx24113_writereg(state, 0x14, r);
+       cx24113_writereg(state, 0x15, (state->bs_freqcnt        & 0xff));
+
+       cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
+       r = (cx24113_readreg(state, 0x17) & 0x0f) |
+               ((state->bs_rdiv & 0x0f) << 4);
+       cx24113_writereg(state, 0x17, r);
+}
+
+#define VGA_0 0x00
+#define VGA_1 0x04
+#define VGA_2 0x02
+#define VGA_3 0x06
+#define VGA_4 0x01
+#define VGA_5 0x05
+#define VGA_6 0x03
+#define VGA_7 0x07
+
+#define RFVGA_0 0x00
+#define RFVGA_1 0x01
+#define RFVGA_2 0x02
+#define RFVGA_3 0x03
+
+static int cx24113_set_gain_settings(struct cx24113_state *state,
+               s16 power_estimation)
+{
+       u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
+          vga    = cx24113_readreg(state, 0x1f) & 0x3f,
+          rfvga  = cx24113_readreg(state, 0x20) & 0xf3;
+       u8 gain_level = power_estimation >= state->tuner_gain_thres;
+
+       dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
+                       power_estimation, state->tuner_gain_thres,
+                       state->gain_level, gain_level);
+
+       if (gain_level == state->gain_level)
+               return 0; /* nothing to be done */
+
+       ampout |= 0xf;
+
+       if (gain_level) {
+               rfvga |= RFVGA_0 << 2;
+               vga   |= (VGA_7 << 3) | VGA_7;
+       } else {
+               rfvga |= RFVGA_2 << 2;
+               vga  |= (VGA_6 << 3) | VGA_2;
+       }
+       state->gain_level = gain_level;
+
+       cx24113_writereg(state, 0x1d, ampout);
+       cx24113_writereg(state, 0x1f, vga);
+       cx24113_writereg(state, 0x20, rfvga);
+
+       return 1; /* did something */
+}
+
+static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
+{
+       u8 xtal = cx24113_readreg(state, 0x02);
+       if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+               high = 1;
+
+       xtal &= ~0x2;
+       if (high)
+               xtal |= high << 1;
+       return cx24113_writereg(state, 0x02, xtal);
+}
+
+static int cx24113_enable(struct cx24113_state *state, u8 enable)
+{
+       u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
+       if (state->rev == REV_CX24113)
+               r21 |= (1 << 1);
+       return cx24113_writereg(state, 0x21, r21);
+}
+
+static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
+{
+       u8 r;
+
+       if (bandwidth_khz <= 19000)
+               r = 0x03 << 6;
+       else if (bandwidth_khz <= 25000)
+               r = 0x02 << 6;
+       else
+               r = 0x01 << 6;
+
+       dprintk("bandwidth to be set: %d\n", bandwidth_khz);
+       bandwidth_khz *= 10;
+       bandwidth_khz -= 10000;
+       bandwidth_khz /= 1000;
+       bandwidth_khz += 5;
+       bandwidth_khz /= 10;
+
+       dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
+
+       r |= bandwidth_khz & 0x3f;
+
+       return cx24113_writereg(state, 0x1e, r);
+}
+
+static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
+{
+       u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
+       return cx24113_writereg(state, 0x10, r);
+}
+
+static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
+       if (r)
+               *status |= TUNER_STATUS_LOCKED;
+       dprintk("PLL locked: %d\n", r);
+       return 0;
+}
+
+static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
+{
+       if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+               refdiv = 2;
+       return state->refdiv = refdiv;
+}
+
+static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
+{
+       s32 N;
+       s64 F;
+       u8 R, r;
+       u8 vcodiv;
+       u8 factor;
+       s32 freq_hz = state->frequency * 1000;
+
+       if (state->config->xtal_khz < 20000)
+               factor = 1;
+       else
+               factor = 2;
+
+       if (state->rev == REV_CX24113) {
+               if (state->frequency >= 1100000)
+                       vcodiv = VCODIV2;
+               else
+                       vcodiv = VCODIV4;
+       } else {
+               if (state->frequency >= 1165000)
+                       vcodiv = VCODIV2;
+               else
+                       vcodiv = VCODIV4;
+       }
+       state->vcodiv = vcodiv;
+
+       dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
+       R = 0;
+       do {
+               R = cx24113_set_ref_div(state, R + 1);
+
+               /* calculate tuner PLL settings: */
+               N =  (freq_hz / 100 * vcodiv) * R;
+               N /= (state->config->xtal_khz) * factor * 2;
+               N += 5;     /* For round up. */
+               N /= 10;
+               N -= 32;
+       } while (N < 6 && R < 3);
+
+       if (N < 6) {
+               err("strange frequency: N < 6\n");
+               return;
+       }
+       F = freq_hz;
+       F *= (u64) (R * vcodiv * 262144);
+       dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+       do_div(F, state->config->xtal_khz*1000 * factor * 2);
+       dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+       F -= (N + 32) * 262144;
+
+       dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+
+       if (state->Fwindow_enabled) {
+               if (F > (262144 / 2 - 1638))
+                       F = 262144 / 2 - 1638;
+               if (F < (-262144 / 2 + 1638))
+                       F = -262144 / 2 + 1638;
+               if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
+                       F = 0;
+                       r = cx24113_readreg(state, 0x10);
+                       cx24113_writereg(state, 0x10, r | (1 << 6));
+               }
+       }
+       dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+
+       *n = (u16) N;
+       *f = (s32) F;
+}
+
+
+static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
+{
+       u8 reg;
+       cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
+
+       reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
+       cx24113_writereg(state, 0x1a, reg);
+
+       cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
+
+       reg = cx24113_readreg(state, 0x1c) & 0x1f;
+       cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
+
+       cx24113_set_Fref(state, r - 1);
+}
+
+static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
+{
+       u8 r = 1; /* or 2 */
+       u16 n = 6;
+       s32 f = 0;
+
+       r = cx24113_readreg(state, 0x14);
+       cx24113_writereg(state, 0x14, r & 0x3f);
+
+       r = cx24113_readreg(state, 0x10);
+       cx24113_writereg(state, 0x10, r & 0xbf);
+
+       state->frequency = frequency;
+
+       dprintk("tuning to frequency: %d\n", frequency);
+
+       cx24113_calc_pll_nf(state, &n, &f);
+       cx24113_set_nfr(state, n, f, state->refdiv);
+
+       r = cx24113_readreg(state, 0x18) & 0xbf;
+       if (state->vcodiv != VCODIV2)
+               r |= 1 << 6;
+       cx24113_writereg(state, 0x18, r);
+
+       /* The need for this sleep is not clear. But helps in some cases */
+       msleep(5);
+
+       r = cx24113_readreg(state, 0x1c) & 0xef;
+       cx24113_writereg(state, 0x1c, r | (1 << 4));
+       return 0;
+}
+
+static int cx24113_init(struct dvb_frontend *fe)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       int ret;
+
+       state->tuner_gain_thres = -50;
+       state->gain_level = 255; /* to force a gain-setting initialization */
+       state->icp_mode = 0;
+
+       if (state->config->xtal_khz < 11000) {
+               state->icp_auto_hi  = ICP_LEVEL4;
+               state->icp_auto_mhi  = ICP_LEVEL4;
+               state->icp_auto_mlow = ICP_LEVEL3;
+               state->icp_auto_low = ICP_LEVEL3;
+       } else {
+               state->icp_auto_hi  = ICP_LEVEL4;
+               state->icp_auto_mhi  = ICP_LEVEL4;
+               state->icp_auto_mlow = ICP_LEVEL3;
+               state->icp_auto_low = ICP_LEVEL2;
+       }
+
+       state->icp_dig = ICP_LEVEL3;
+       state->icp_man = ICP_LEVEL1;
+       state->acp_on  = 1;
+       state->vco_mode = 0;
+       state->vco_shift = 0;
+       state->vco_band = VCOBANDSEL_1;
+       state->bs_delay = 8;
+       state->bs_freqcnt = 0x0fff;
+       state->bs_rdiv = 0x0fff;
+       state->prescaler_mode = 0;
+       state->lna_gain = LNA_MAX_GAIN;
+       state->rfvga_bias_ctrl = 1;
+       state->Fwindow_enabled = 1;
+
+       cx24113_set_Fref(state, 0);
+       cx24113_enable(state, 0x3d);
+       cx24113_set_parameters(state);
+
+       cx24113_set_gain_settings(state, -30);
+
+       cx24113_set_bandwidth(state, 18025);
+       cx24113_set_clk_inversion(state, 1);
+
+       if (state->config->xtal_khz >= 40000)
+               ret = cx24113_writereg(state, 0x02,
+                       (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
+       else
+               ret = cx24113_writereg(state, 0x02,
+                       (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
+
+       return ret;
+}
+
+static int cx24113_set_params(struct dvb_frontend *fe,
+               struct dvb_frontend_parameters *p)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
+       u32 roll_off = 675;
+       u32 bw;
+
+       bw  = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000;
+       bw += (10000000/100) + 5;
+       bw /= 10;
+       bw += 1000;
+       cx24113_set_bandwidth(state, bw);
+
+       cx24113_set_frequency(state, p->frequency);
+       msleep(5);
+       return cx24113_get_status(fe, &bw);
+}
+
+static s8 cx24113_agc_table[2][10] = {
+       {-54, -41, -35, -30, -25, -21, -16, -10,  -6,  -2},
+       {-39, -35, -30, -25, -19, -15, -11,  -5,   1,   9},
+};
+
+void cx24113_agc_callback(struct dvb_frontend *fe)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       s16 s, i;
+       if (!fe->ops.read_signal_strength)
+               return;
+
+       do {
+               /* this only works with the current CX24123 implementation */
+               fe->ops.read_signal_strength(fe, (u16 *) &s);
+               s >>= 8;
+               dprintk("signal strength: %d\n", s);
+               for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
+                       if (cx24113_agc_table[state->gain_level][i] > s)
+                               break;
+               s = -25 - i*5;
+       } while (cx24113_set_gain_settings(state, s));
+}
+EXPORT_SYMBOL(cx24113_agc_callback);
+
+static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       *frequency = state->frequency;
+       return 0;
+}
+
+static int cx24113_release(struct dvb_frontend *fe)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       dprintk("\n");
+       fe->tuner_priv = NULL;
+       kfree(state);
+       return 0;
+}
+
+static const struct dvb_tuner_ops cx24113_tuner_ops = {
+       .info = {
+               .name           = "Conexant CX24113",
+               .frequency_min  = 950000,
+               .frequency_max  = 2150000,
+               .frequency_step = 125,
+       },
+
+       .release       = cx24113_release,
+
+       .init          = cx24113_init,
+       .sleep         = NULL,
+
+       .set_params    = cx24113_set_params,
+       .get_frequency = cx24113_get_frequency,
+       .get_bandwidth = NULL,
+       .get_status    = cx24113_get_status,
+};
+
+struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
+               const struct cx24113_config *config, struct i2c_adapter *i2c)
+{
+       /* allocate memory for the internal state */
+       struct cx24113_state *state =
+               kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
+       int rc;
+       if (state == NULL) {
+               err("Unable to kmalloc\n");
+               goto error;
+       }
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+
+       info("trying to detect myself\n");
+
+       /* making a dummy read, because of some expected troubles
+        * after power on */
+       cx24113_readreg(state, 0x00);
+
+       rc = cx24113_readreg(state, 0x00);
+       if (rc < 0) {
+               info("CX24113 not found.\n");
+               goto error;
+       }
+       state->rev = rc;
+
+       switch (rc) {
+       case 0x43:
+               info("detected CX24113 variant\n");
+               break;
+       case REV_CX24113:
+               info("sucessfully detected\n");
+               break;
+       default:
+               err("unsupported device id: %x\n", state->rev);
+               goto error;
+       }
+       state->ver = cx24113_readreg(state, 0x01);
+       info("version: %x\n", state->ver);
+
+       /* create dvb_frontend */
+       memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
+                       sizeof(struct dvb_tuner_ops));
+       fe->tuner_priv = state;
+       return fe;
+
+error:
+       kfree(state);
+
+       return NULL;
+}
+EXPORT_SYMBOL(cx24113_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
+MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
+MODULE_LICENSE("GPL");
+
index 5ab3dd11076bd7ebe6824c8136e7f9c8b689db08..5de0f7ffd8d2491014a14c09f6d6daa5b62a76db 100644 (file)
@@ -16,7 +16,7 @@
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef CX24113_H
@@ -30,9 +30,13 @@ struct cx24113_config {
        u32 xtal_khz;
 };
 
-/* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \
- * (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */
+#if defined(CONFIG_DVB_TUNER_CX24113) || \
+       (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
+extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
+       const struct cx24113_config *config, struct i2c_adapter *i2c);
 
+extern void cx24113_agc_callback(struct dvb_frontend *fe);
+#else
 static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
        const struct cx24113_config *config, struct i2c_adapter *i2c)
 {
@@ -44,5 +48,6 @@ static inline void cx24113_agc_callback(struct dvb_frontend *fe)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 }
+#endif
 
 #endif /* CX24113_H */
index b144b308a4dd336854226eb1c5ef2484b598b0c2..9b6c89e93f1696570c7bc7194d6deb04a5b21846 100644 (file)
@@ -106,7 +106,7 @@ MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
 #define CX24116_HAS_SYNCLOCK (0x08)
 #define CX24116_HAS_UNKNOWN1 (0x10)
 #define CX24116_HAS_UNKNOWN2 (0x20)
-#define CX24116_STATUS_MASK  (0x3f)
+#define CX24116_STATUS_MASK  (0x0f)
 #define CX24116_SIGNAL_MASK  (0xc0)
 
 #define CX24116_DISEQC_TONEOFF   (0)    /* toneburst never sent */
@@ -160,6 +160,7 @@ struct cx24116_tuning {
        fe_spectral_inversion_t inversion;
        fe_code_rate_t fec;
 
+       fe_delivery_system_t delsys;
        fe_modulation_t modulation;
        fe_pilot_t pilot;
        fe_rolloff_t rolloff;
@@ -411,14 +412,15 @@ struct cx24116_modfec {
 };
 
 static int cx24116_lookup_fecmod(struct cx24116_state *state,
-       fe_modulation_t m, fe_code_rate_t f)
+       fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
 {
        int i, ret = -EOPNOTSUPP;
 
        dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
 
        for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
-               if ((m == CX24116_MODFEC_MODES[i].modulation) &&
+               if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
+                       (m == CX24116_MODFEC_MODES[i].modulation) &&
                        (f == CX24116_MODFEC_MODES[i].fec)) {
                                ret = i;
                                break;
@@ -429,13 +431,13 @@ static int cx24116_lookup_fecmod(struct cx24116_state *state,
 }
 
 static int cx24116_set_fec(struct cx24116_state *state,
-       fe_modulation_t mod, fe_code_rate_t fec)
+       fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
 {
        int ret = 0;
 
        dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
 
-       ret = cx24116_lookup_fecmod(state, mod, fec);
+       ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
 
        if (ret < 0)
                return ret;
@@ -679,7 +681,8 @@ static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
        struct cx24116_state *state = fe->demodulator_priv;
 
-       int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
+       int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
+               CX24116_STATUS_MASK;
 
        dprintk("%s: status = 0x%02x\n", __func__, lock);
 
@@ -1205,7 +1208,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct cx24116_cmd cmd;
        fe_status_t tunerstat;
-       int i, status, ret, retune;
+       int i, status, ret, retune = 1;
 
        dprintk("%s()\n", __func__);
 
@@ -1222,7 +1225,6 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
 
                /* Pilot doesn't exist in DVB-S, turn bit off */
                state->dnxt.pilot_val = CX24116_PILOT_OFF;
-               retune = 1;
 
                /* DVB-S only supports 0.35 */
                if (c->rolloff != ROLLOFF_35) {
@@ -1250,7 +1252,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
                case PILOT_AUTO:        /* Not supported but emulated */
                        state->dnxt.pilot_val = (c->modulation == QPSK)
                                ? CX24116_PILOT_OFF : CX24116_PILOT_ON;
-                       retune = 2;
+                       retune++;
                        break;
                case PILOT_OFF:
                        state->dnxt.pilot_val = CX24116_PILOT_OFF;
@@ -1287,6 +1289,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
                        __func__, c->delivery_system);
                return -EOPNOTSUPP;
        }
+       state->dnxt.delsys = c->delivery_system;
        state->dnxt.modulation = c->modulation;
        state->dnxt.frequency = c->frequency;
        state->dnxt.pilot = c->pilot;
@@ -1297,7 +1300,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
                return ret;
 
        /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
-       ret = cx24116_set_fec(state, c->modulation, c->fec_inner);
+       ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
        if (ret !=  0)
                return ret;
 
@@ -1308,6 +1311,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
        /* discard the 'current' tuning parameters and prepare to tune */
        cx24116_clone_params(fe);
 
+       dprintk("%s:   delsys      = %d\n", __func__, state->dcur.delsys);
        dprintk("%s:   modulation  = %d\n", __func__, state->dcur.modulation);
        dprintk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
        dprintk("%s:   pilot       = %d (val = 0x%02x)\n", __func__,
@@ -1427,6 +1431,23 @@ tuned:  /* Set/Reset B/W */
        return ret;
 }
 
+static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
+       unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
+{
+       *delay = HZ / 5;
+       if (params) {
+               int ret = cx24116_set_frontend(fe, params);
+               if (ret)
+                       return ret;
+       }
+       return cx24116_read_status(fe, status);
+}
+
+static int cx24116_get_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_HW;
+}
+
 static struct dvb_frontend_ops cx24116_ops = {
 
        .info = {
@@ -1458,6 +1479,8 @@ static struct dvb_frontend_ops cx24116_ops = {
        .set_voltage = cx24116_set_voltage,
        .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
        .diseqc_send_burst = cx24116_diseqc_send_burst,
+       .get_frontend_algo = cx24116_get_algo,
+       .tune = cx24116_tune,
 
        .set_property = cx24116_set_property,
        .get_property = cx24116_get_property,
index 3e81268571276f895e2c1d6075d2ba44209953f7..aab8112e2db20f6658c66c0c83cee0e9ae6fd4f7 100644 (file)
@@ -66,7 +66,8 @@ struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
        return NULL;
 }
 
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+static inline
+int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
                                    int no_of_demods, u8 default_addr,
                                    struct dib7000p_config cfg[])
 {
@@ -74,13 +75,15 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
        return -ENODEV;
 }
 
-extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+static inline
+int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
 }
 
-extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+static inline
+int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
index b9ca5c8d2dd9400814f64566a24952b541126a0a..ec4e08dbc699c78a31432a470d1292d1261ca312 100644 (file)
@@ -39,7 +39,7 @@ static const char mod_name[] = "drx397xD";
 #define F_SET_0D4h     2
 
 enum fw_ix {
-#define _FW_ENTRY(a, b)                b
+#define _FW_ENTRY(a, b, c)     b
 #include "drx397xD_fw.h"
 };
 
@@ -72,11 +72,11 @@ static struct {
        int refcnt;
        const u8 *data[ARRAY_SIZE(blob_name)];
 } fw[] = {
-#define _FW_ENTRY(a, b)                {                       \
-                       .name   = a,                    \
-                       .file   = 0,                    \
-                       .lock   = RW_LOCK_UNLOCKED,     \
-                       .refcnt = 0,                    \
+#define _FW_ENTRY(a, b, c)     {                                       \
+                       .name   = a,                                    \
+                       .file   = 0,                                    \
+                       .lock   = __RW_LOCK_UNLOCKED(fw[c].lock),       \
+                       .refcnt = 0,                                    \
                        .data   = { }           }
 #include "drx397xD_fw.h"
 };
index 01de02a81cd41ea27f30405d8a33119eaf1450d4..c8b44c1e807f892866f0c3e3cdb2963dee576422 100644 (file)
@@ -18,8 +18,8 @@
  */
 
 #ifdef _FW_ENTRY
-       _FW_ENTRY("drx397xD.A2.fw",     DRXD_FW_A2 = 0          ),
-       _FW_ENTRY("drx397xD.B1.fw",     DRXD_FW_B1              ),
+       _FW_ENTRY("drx397xD.A2.fw",     DRXD_FW_A2 = 0, DRXD_FW_A2      ),
+       _FW_ENTRY("drx397xD.B1.fw",     DRXD_FW_B1,     DRXD_FW_B1      ),
 #undef _FW_ENTRY
 #endif /* _FW_ENTRY */
 
index ea058153ebfa3dfd8e88660662fd7e4fa3f9ee50..9f6349964cdafa53b49525b494e4c7066e4ed903 100644 (file)
@@ -311,7 +311,7 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
        .count = 4,
        .entries = {
                { 1250000, 500, 0xc4, 0x00},
-               { 1550000, 500, 0xc4, 0x40},
+               { 1450000, 500, 0xc4, 0x40},
                { 2050000, 500, 0xc4, 0x80},
                { 2150000, 500, 0xc4, 0xc0},
        },
diff --git a/drivers/media/dvb/frontends/lgdt3304.c b/drivers/media/dvb/frontends/lgdt3304.c
new file mode 100644 (file)
index 0000000..469ace5
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Driver for LG ATSC lgdt3304 driver
+ *
+ * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "lgdt3304.h"
+
+static  unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
+
+#define dprintk(fmt, args...) if (debug) do {\
+                       printk("lgdt3304 debug: " fmt, ##args); } while (0)
+
+struct lgdt3304_state
+{
+       struct dvb_frontend frontend;
+       fe_modulation_t current_modulation;
+       __u32 snr;
+       __u32 current_frequency;
+       __u8 addr;
+       struct i2c_adapter *i2c;
+};
+
+static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
+{
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       struct i2c_msg i2cmsgs = {
+               .addr = state->addr,
+               .flags = 0,
+               .len = 3,
+               .buf = buf
+       };
+       int i;
+       int err;
+
+       for (i=0; i<len-1; i+=3){
+               if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
+                       printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
+                       if (err < 0)
+                               return err;
+                       else
+                               return -EREMOTEIO;
+               }
+               i2cmsgs.buf += 3;
+       }
+       return 0;
+}
+
+static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
+{
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       struct i2c_msg i2cmsgs[2];
+       int ret;
+       __u8 buf;
+
+       __u8 regbuf[2] = { reg>>8, reg&0xff };
+
+       i2cmsgs[0].addr = state->addr;
+       i2cmsgs[0].flags = 0;
+       i2cmsgs[0].len = 2;
+       i2cmsgs[0].buf = regbuf;
+
+       i2cmsgs[1].addr = state->addr;
+       i2cmsgs[1].flags = I2C_M_RD;
+       i2cmsgs[1].len = 1;
+       i2cmsgs[1].buf = &buf;
+
+       if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
+               printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
+               return ret;
+       }
+
+       return buf;
+}
+
+static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
+{
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       char buffer[3] = { reg>>8, reg&0xff, val };
+       int ret;
+
+       struct i2c_msg i2cmsgs = {
+               .addr = state->addr,
+               .flags = 0,
+               .len = 3,
+               .buf=buffer
+       };
+       ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
+       if (ret != 1) {
+               printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+
+static int lgdt3304_soft_Reset(struct dvb_frontend *fe)
+{
+       lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a);
+       lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b);
+       mdelay(200);
+       return 0;
+}
+
+static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
+       int err = 0;
+
+       static __u8 lgdt3304_vsb8_data[] = {
+               /* 16bit  , 8bit */
+               /* regs   , val  */
+               0x00, 0x00, 0x02,
+               0x00, 0x00, 0x13,
+               0x00, 0x0d, 0x02,
+               0x00, 0x0e, 0x02,
+               0x00, 0x12, 0x32,
+               0x00, 0x13, 0xc4,
+               0x01, 0x12, 0x17,
+               0x01, 0x13, 0x15,
+               0x01, 0x14, 0x18,
+               0x01, 0x15, 0xff,
+               0x01, 0x16, 0x2c,
+               0x02, 0x14, 0x67,
+               0x02, 0x24, 0x8d,
+               0x04, 0x27, 0x12,
+               0x04, 0x28, 0x4f,
+               0x03, 0x08, 0x80,
+               0x03, 0x09, 0x00,
+               0x03, 0x0d, 0x00,
+               0x03, 0x0e, 0x1c,
+               0x03, 0x14, 0xe1,
+               0x05, 0x0e, 0x5b,
+       };
+
+       /* not yet tested .. */
+       static __u8 lgdt3304_qam64_data[] = {
+               /* 16bit  , 8bit */
+               /* regs   , val  */
+               0x00, 0x00, 0x18,
+               0x00, 0x0d, 0x02,
+               //0x00, 0x0e, 0x02,
+               0x00, 0x12, 0x2a,
+               0x00, 0x13, 0x00,
+               0x03, 0x14, 0xe3,
+               0x03, 0x0e, 0x1c,
+               0x03, 0x08, 0x66,
+               0x03, 0x09, 0x66,
+               0x03, 0x0a, 0x08,
+               0x03, 0x0b, 0x9b,
+               0x05, 0x0e, 0x5b,
+       };
+
+
+       /* tested with KWorld a340 */
+       static __u8 lgdt3304_qam256_data[] = {
+               /* 16bit  , 8bit */
+               /* regs   , val  */
+               0x00, 0x00, 0x01,  //0x19,
+               0x00, 0x12, 0x2a,
+               0x00, 0x13, 0x80,
+               0x00, 0x0d, 0x02,
+               0x03, 0x14, 0xe3,
+
+               0x03, 0x0e, 0x1c,
+               0x03, 0x08, 0x66,
+               0x03, 0x09, 0x66,
+               0x03, 0x0a, 0x08,
+               0x03, 0x0b, 0x9b,
+
+               0x03, 0x0d, 0x14,
+               //0x05, 0x0e, 0x5b,
+               0x01, 0x06, 0x4a,
+               0x01, 0x07, 0x3d,
+               0x01, 0x08, 0x70,
+               0x01, 0x09, 0xa3,
+
+               0x05, 0x04, 0xfd,
+
+               0x00, 0x0d, 0x82,
+
+               0x05, 0x0e, 0x5b,
+
+               0x05, 0x0e, 0x5b,
+
+               0x00, 0x02, 0x9a,
+
+               0x00, 0x02, 0x9b,
+
+               0x00, 0x00, 0x01,
+               0x00, 0x12, 0x2a,
+               0x00, 0x13, 0x80,
+               0x00, 0x0d, 0x02,
+               0x03, 0x14, 0xe3,
+
+               0x03, 0x0e, 0x1c,
+               0x03, 0x08, 0x66,
+               0x03, 0x09, 0x66,
+               0x03, 0x0a, 0x08,
+               0x03, 0x0b, 0x9b,
+
+               0x03, 0x0d, 0x14,
+               0x01, 0x06, 0x4a,
+               0x01, 0x07, 0x3d,
+               0x01, 0x08, 0x70,
+               0x01, 0x09, 0xa3,
+
+               0x05, 0x04, 0xfd,
+
+               0x00, 0x0d, 0x82,
+
+               0x05, 0x0e, 0x5b,
+       };
+
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       if (state->current_modulation != param->u.vsb.modulation) {
+               switch(param->u.vsb.modulation) {
+               case VSB_8:
+                       err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data,
+                                       sizeof(lgdt3304_vsb8_data));
+                       break;
+               case QAM_64:
+                       err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data,
+                                       sizeof(lgdt3304_qam64_data));
+                       break;
+               case QAM_256:
+                       err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data,
+                                       sizeof(lgdt3304_qam256_data));
+                       break;
+               default:
+                       break;
+               }
+
+               if (err) {
+                       printk("%s error setting modulation\n", __FUNCTION__);
+               } else {
+                       state->current_modulation = param->u.vsb.modulation;
+               }
+       }
+       state->current_frequency = param->frequency;
+
+       lgdt3304_soft_Reset(fe);
+
+
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, param);
+
+       return 0;
+}
+
+static int lgdt3304_init(struct dvb_frontend *fe) {
+       return 0;
+}
+
+static int lgdt3304_sleep(struct dvb_frontend *fe) {
+       return 0;
+}
+
+
+static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       int r011d;
+       int qam_lck;
+
+       *status = 0;
+       dprintk("lgdt read status\n");
+
+       r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
+
+       dprintk("%02x\n", r011d);
+
+       switch(state->current_modulation) {
+       case VSB_8:
+               if (r011d & 0x80) {
+                       dprintk("VSB Locked\n");
+                       *status |= FE_HAS_CARRIER;
+                       *status |= FE_HAS_LOCK;
+                       *status |= FE_HAS_SYNC;
+                       *status |= FE_HAS_SIGNAL;
+               }
+               break;
+       case QAM_64:
+       case QAM_256:
+               qam_lck = r011d & 0x7;
+               switch(qam_lck) {
+                       case 0x0: dprintk("Unlock\n");
+                                 break;
+                       case 0x4: dprintk("1st Lock in acquisition state\n");
+                                 break;
+                       case 0x6: dprintk("2nd Lock in acquisition state\n");
+                                 break;
+                       case 0x7: dprintk("Final Lock in good reception state\n");
+                                 *status |= FE_HAS_CARRIER;
+                                 *status |= FE_HAS_LOCK;
+                                 *status |= FE_HAS_SYNC;
+                                 *status |= FE_HAS_SIGNAL;
+                                 break;
+               }
+               break;
+       default:
+               printk("%s unhandled modulation\n", __FUNCTION__);
+       }
+
+
+       return 0;
+}
+
+static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
+{
+       dprintk("read ber\n");
+       return 0;
+}
+
+static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
+{
+       dprintk("read snr\n");
+       return 0;
+}
+
+static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
+{
+       dprintk("read ucblocks\n");
+       return 0;
+}
+
+static void lgdt3304_release(struct dvb_frontend *fe)
+{
+       struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops demod_lgdt3304={
+       .info = {
+               .name = "LG 3304",
+               .type = FE_ATSC,
+               .frequency_min = 54000000,
+               .frequency_max = 858000000,
+               .frequency_stepsize = 62500,
+               .symbol_rate_min = 5056941,
+               .symbol_rate_max = 10762000,
+               .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+       },
+       .init = lgdt3304_init,
+       .sleep = lgdt3304_sleep,
+       .set_frontend = lgdt3304_set_parameters,
+       .read_snr = lgdt3304_read_snr,
+       .read_ber = lgdt3304_read_ber,
+       .read_status = lgdt3304_read_status,
+       .read_ucblocks = lgdt3304_read_ucblocks,
+       .release = lgdt3304_release,
+};
+
+struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
+                                          struct i2c_adapter *i2c)
+{
+
+       struct lgdt3304_state *state;
+       state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
+       memset(state, 0x0, sizeof(struct lgdt3304_state));
+       state->addr = config->i2c_address;
+       state->i2c = i2c;
+
+       memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+}
+
+EXPORT_SYMBOL_GPL(lgdt3304_attach);
+MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
+MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgdt3304.h b/drivers/media/dvb/frontends/lgdt3304.h
new file mode 100644 (file)
index 0000000..fc409fe
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  Driver for DVB-T lgdt3304 demodulator
+ *
+ *  Copyright (C) 2008 Markus Rechberger <mrechberger@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 LGDT3304_H
+#define LGDT3304_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgdt3304_config
+{
+       /* demodulator's I2C address */
+       u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE))
+extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
+                                          struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
+                                          struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_LGDT */
+
+#endif /* LGDT3304_H */
index 40644aacffcb218dbbee77ee8a8b80e15b2b0164..66e2dd6d6fe4eb725b21f203b21e180081c8ef45 100644 (file)
@@ -874,6 +874,9 @@ struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
        /* Note: Leaving the I2C gate open here. */
        s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
 
+       /* Put the device into low-power mode until first use */
+       s5h1411_set_powerstate(&state->frontend, 1);
+
        return &state->frontend;
 
 error:
diff --git a/drivers/media/dvb/frontends/s921_core.c b/drivers/media/dvb/frontends/s921_core.c
new file mode 100644 (file)
index 0000000..974b52b
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Driver for Sharp s921 driver
+ *
+ * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "s921_core.h"
+
+static int s921_isdb_init(struct s921_isdb_t *dev);
+static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params);
+static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params);
+static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data);
+
+static u8 init_table[]={ 0x01, 0x40, 0x02, 0x00, 0x03, 0x40, 0x04, 0x01,
+                        0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
+                        0x09, 0x00, 0x0a, 0x00, 0x0b, 0x5a, 0x0c, 0x00,
+                        0x0d, 0x00, 0x0f, 0x00, 0x13, 0x1b, 0x14, 0x80,
+                        0x15, 0x40, 0x17, 0x70, 0x18, 0x01, 0x19, 0x12,
+                        0x1a, 0x01, 0x1b, 0x12, 0x1c, 0xa0, 0x1d, 0x00,
+                        0x1e, 0x0a, 0x1f, 0x08, 0x20, 0x40, 0x21, 0xff,
+                        0x22, 0x4c, 0x23, 0x4e, 0x24, 0x4c, 0x25, 0x00,
+                        0x26, 0x00, 0x27, 0xf4, 0x28, 0x60, 0x29, 0x88,
+                        0x2a, 0x40, 0x2b, 0x40, 0x2c, 0xff, 0x2d, 0x00,
+                        0x2e, 0xff, 0x2f, 0x00, 0x30, 0x20, 0x31, 0x06,
+                        0x32, 0x0c, 0x34, 0x0f, 0x37, 0xfe, 0x38, 0x00,
+                        0x39, 0x63, 0x3a, 0x10, 0x3b, 0x10, 0x47, 0x00,
+                        0x49, 0xe5, 0x4b, 0x00, 0x50, 0xc0, 0x52, 0x20,
+                        0x54, 0x5a, 0x55, 0x5b, 0x56, 0x40, 0x57, 0x70,
+                        0x5c, 0x50, 0x5d, 0x00, 0x62, 0x17, 0x63, 0x2f,
+                        0x64, 0x6f, 0x68, 0x00, 0x69, 0x89, 0x6a, 0x00,
+                        0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00,
+                        0x70, 0x00, 0x71, 0x00, 0x75, 0x00, 0x76, 0x30,
+                        0x77, 0x01, 0xaf, 0x00, 0xb0, 0xa0, 0xb2, 0x3d,
+                        0xb3, 0x25, 0xb4, 0x8b, 0xb5, 0x4b, 0xb6, 0x3f,
+                        0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xfc, 0xba, 0x00,
+                        0xbb, 0x00, 0xbc, 0x00, 0xd0, 0x30, 0xe4, 0x84,
+                        0xf0, 0x48, 0xf1, 0x19, 0xf2, 0x5a, 0xf3, 0x8e,
+                        0xf4, 0x2d, 0xf5, 0x07, 0xf6, 0x5a, 0xf7, 0xba,
+                        0xf8, 0xd7 };
+
+static u8 c_table[]={ 0x58, 0x8a, 0x7b, 0x59, 0x8c, 0x7b, 0x5a, 0x8e, 0x5b,
+                     0x5b, 0x90, 0x5b, 0x5c, 0x92, 0x5b, 0x5d, 0x94, 0x5b,
+                     0x5e, 0x96, 0x5b, 0x5f, 0x98, 0x3b, 0x60, 0x9a, 0x3b,
+                     0x61, 0x9c, 0x3b, 0x62, 0x9e, 0x3b, 0x63, 0xa0, 0x3b,
+                     0x64, 0xa2, 0x1b, 0x65, 0xa4, 0x1b, 0x66, 0xa6, 0x1b,
+                     0x67, 0xa8, 0x1b, 0x68, 0xaa, 0x1b, 0x69, 0xac, 0x1b,
+                     0x6a, 0xae, 0x1b, 0x6b, 0xb0, 0x1b, 0x6c, 0xb2, 0x1b,
+                     0x6d, 0xb4, 0xfb, 0x6e, 0xb6, 0xfb, 0x6f, 0xb8, 0xfb,
+                     0x70, 0xba, 0xfb, 0x71, 0xbc, 0xdb, 0x72, 0xbe, 0xdb,
+                     0x73, 0xc0, 0xdb, 0x74, 0xc2, 0xdb, 0x75, 0xc4, 0xdb,
+                     0x76, 0xc6, 0xdb, 0x77, 0xc8, 0xbb, 0x78, 0xca, 0xbb,
+                     0x79, 0xcc, 0xbb, 0x7a, 0xce, 0xbb, 0x7b, 0xd0, 0xbb,
+                     0x7c, 0xd2, 0xbb, 0x7d, 0xd4, 0xbb, 0x7e, 0xd6, 0xbb,
+                     0x7f, 0xd8, 0xbb, 0x80, 0xda, 0x9b, 0x81, 0xdc, 0x9b,
+                     0x82, 0xde, 0x9b, 0x83, 0xe0, 0x9b, 0x84, 0xe2, 0x9b,
+                     0x85, 0xe4, 0x9b, 0x86, 0xe6, 0x9b, 0x87, 0xe8, 0x9b,
+                     0x88, 0xea, 0x9b, 0x89, 0xec, 0x9b };
+
+int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data) {
+       switch(cmd) {
+       case ISDB_T_CMD_INIT:
+               s921_isdb_init(dev);
+               break;
+       case ISDB_T_CMD_SET_PARAM:
+               s921_isdb_set_parameters(dev, data);
+               break;
+       case ISDB_T_CMD_TUNE:
+               s921_isdb_tune(dev, data);
+               break;
+       case ISDB_T_CMD_GET_STATUS:
+               s921_isdb_get_status(dev, data);
+               break;
+       default:
+               printk("unhandled command\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s921_isdb_init(struct s921_isdb_t *dev) {
+       unsigned int i;
+       unsigned int ret;
+       printk("isdb_init\n");
+       for (i = 0; i < sizeof(init_table); i+=2) {
+               ret = dev->i2c_write(dev->priv_dev, init_table[i], init_table[i+1]);
+               if (ret != 0) {
+                       printk("i2c write failed\n");
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params) {
+
+       int ret;
+       /* auto is sufficient for now, lateron this should be reflected in an extra interface */
+
+
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb0, 0xa0); //mod_b2);
+       ret = dev->i2c_write(dev->priv_dev, 0xb2, 0x3d); //mod_b2);
+
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb3, 0x25); //mod_b3);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb4, 0x8b); //mod_b4);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb5, 0x4b); //mod_b5);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb6, 0x3f); //mod_b6);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb7, 0x3f); //mod_b7);
+       if (ret < 0)
+               return -EINVAL;
+
+       return E_OK;
+}
+
+static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params) {
+
+       int ret;
+       int index;
+
+       index = (params->frequency - 473143000)/6000000;
+
+       if (index > 48) {
+               return -EINVAL;
+       }
+
+       dev->i2c_write(dev->priv_dev, 0x47, 0x60);
+
+       ret = dev->i2c_write(dev->priv_dev, 0x68, 0x00);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0x69, 0x89);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf0, 0x48);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf1, 0x19);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf2, c_table[index*3]);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf3, c_table[index*3+1]);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf4, c_table[index*3+2]);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf5, 0xae);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf6, 0xb7);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf7, 0xba);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf8, 0xd7);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0x68, 0x0a);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0x69, 0x09);
+       if (ret < 0)
+               return -EINVAL;
+
+       dev->i2c_write(dev->priv_dev, 0x01, 0x40);
+       return 0;
+}
+
+static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data) {
+       unsigned int *ret = (unsigned int*)data;
+       u8 ifagc_dt;
+       u8 rfagc_dt;
+
+       mdelay(10);
+       ifagc_dt = dev->i2c_read(dev->priv_dev, 0x81);
+       rfagc_dt = dev->i2c_read(dev->priv_dev, 0x82);
+       if (rfagc_dt == 0x40) {
+               *ret = 1;
+       }
+       return 0;
+}
diff --git a/drivers/media/dvb/frontends/s921_core.h b/drivers/media/dvb/frontends/s921_core.h
new file mode 100644 (file)
index 0000000..de2f10a
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef _S921_CORE_H
+#define _S921_CORE_H
+//#define u8 unsigned int
+//#define u32 unsigned int
+
+
+
+//#define EINVAL -1
+#define E_OK 0
+
+struct s921_isdb_t {
+       void *priv_dev;
+       int (*i2c_write)(void *dev, u8 reg, u8 val);
+       int (*i2c_read)(void *dev, u8 reg);
+};
+
+#define ISDB_T_CMD_INIT       0
+#define ISDB_T_CMD_SET_PARAM  1
+#define ISDB_T_CMD_TUNE       2
+#define ISDB_T_CMD_GET_STATUS 3
+
+struct s921_isdb_t_tune_params {
+       u32 frequency;
+};
+
+struct s921_isdb_t_status {
+};
+
+struct s921_isdb_t_transmission_mode_params {
+       u8 mode;
+       u8 layer_a_mode;
+#define ISDB_T_LA_MODE_1 0
+#define ISDB_T_LA_MODE_2 1
+#define ISDB_T_LA_MODE_3 2
+       u8 layer_a_carrier_modulation;
+#define ISDB_T_LA_CM_DQPSK 0
+#define ISDB_T_LA_CM_QPSK  1
+#define ISDB_T_LA_CM_16QAM 2
+#define ISDB_T_LA_CM_64QAM 3
+#define ISDB_T_LA_CM_NOLAYER 4
+       u8 layer_a_code_rate;
+#define ISDB_T_LA_CR_1_2   0
+#define ISDB_T_LA_CR_2_3   1
+#define ISDB_T_LA_CR_3_4   2
+#define ISDB_T_LA_CR_5_6   4
+#define ISDB_T_LA_CR_7_8   8
+#define ISDB_T_LA_CR_NOLAYER   16
+       u8 layer_a_time_interleave;
+#define ISDB_T_LA_TI_0  0
+#define ISDB_T_LA_TI_1  1
+#define ISDB_T_LA_TI_2  2
+#define ISDB_T_LA_TI_4  4
+#define ISDB_T_LA_TI_8  8
+#define ISDB_T_LA_TI_16 16
+#define ISDB_T_LA_TI_32 32
+       u8 layer_a_nseg;
+
+       u8 layer_b_mode;
+#define ISDB_T_LB_MODE_1 0
+#define ISDB_T_LB_MODE_2 1
+#define ISDB_T_LB_MODE_3 2
+       u8 layer_b_carrier_modulation;
+#define ISDB_T_LB_CM_DQPSK 0
+#define ISDB_T_LB_CM_QPSK  1
+#define ISDB_T_LB_CM_16QAM 2
+#define ISDB_T_LB_CM_64QAM 3
+#define ISDB_T_LB_CM_NOLAYER 4
+       u8 layer_b_code_rate;
+#define ISDB_T_LB_CR_1_2   0
+#define ISDB_T_LB_CR_2_3   1
+#define ISDB_T_LB_CR_3_4   2
+#define ISDB_T_LB_CR_5_6   4
+#define ISDB_T_LB_CR_7_8   8
+#define ISDB_T_LB_CR_NOLAYER   16
+       u8 layer_b_time_interleave;
+#define ISDB_T_LB_TI_0  0
+#define ISDB_T_LB_TI_1  1
+#define ISDB_T_LB_TI_2  2
+#define ISDB_T_LB_TI_4  4
+#define ISDB_T_LB_TI_8  8
+#define ISDB_T_LB_TI_16 16
+#define ISDB_T_LB_TI_32 32
+       u8 layer_b_nseg;
+
+       u8 layer_c_mode;
+#define ISDB_T_LC_MODE_1 0
+#define ISDB_T_LC_MODE_2 1
+#define ISDB_T_LC_MODE_3 2
+       u8 layer_c_carrier_modulation;
+#define ISDB_T_LC_CM_DQPSK 0
+#define ISDB_T_LC_CM_QPSK  1
+#define ISDB_T_LC_CM_16QAM 2
+#define ISDB_T_LC_CM_64QAM 3
+#define ISDB_T_LC_CM_NOLAYER 4
+       u8 layer_c_code_rate;
+#define ISDB_T_LC_CR_1_2   0
+#define ISDB_T_LC_CR_2_3   1
+#define ISDB_T_LC_CR_3_4   2
+#define ISDB_T_LC_CR_5_6   4
+#define ISDB_T_LC_CR_7_8   8
+#define ISDB_T_LC_CR_NOLAYER   16
+       u8 layer_c_time_interleave;
+#define ISDB_T_LC_TI_0  0
+#define ISDB_T_LC_TI_1  1
+#define ISDB_T_LC_TI_2  2
+#define ISDB_T_LC_TI_4  4
+#define ISDB_T_LC_TI_8  8
+#define ISDB_T_LC_TI_16 16
+#define ISDB_T_LC_TI_32 32
+       u8 layer_c_nseg;
+};
+
+int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
+#endif
diff --git a/drivers/media/dvb/frontends/s921_module.c b/drivers/media/dvb/frontends/s921_module.c
new file mode 100644 (file)
index 0000000..3cbb9cb
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Driver for Sharp s921 driver
+ *
+ * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
+ *
+ * All rights reserved.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "s921_module.h"
+#include "s921_core.h"
+
+static  unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"s921 debugging (default off)");
+
+#define dprintk(fmt, args...) if (debug) do {\
+                       printk("s921 debug: " fmt, ##args); } while (0)
+
+struct s921_state
+{
+       struct dvb_frontend frontend;
+       fe_modulation_t current_modulation;
+       __u32 snr;
+       __u32 current_frequency;
+       __u8 addr;
+       struct s921_isdb_t dev;
+       struct i2c_adapter *i2c;
+};
+
+static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
+       struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
+       struct s921_isdb_t_transmission_mode_params params;
+       struct s921_isdb_t_tune_params tune_params;
+
+       tune_params.frequency = param->frequency;
+       s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, &params);
+       s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params);
+       mdelay(100);
+       return 0;
+}
+
+static int s921_init(struct dvb_frontend *fe) {
+       printk("s921 init\n");
+       return 0;
+}
+
+static int s921_sleep(struct dvb_frontend *fe) {
+       printk("s921 sleep\n");
+       return 0;
+}
+
+static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
+       unsigned int ret;
+       mdelay(5);
+       s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret);
+       *status = 0;
+
+       printk("status: %02x\n", ret);
+       if (ret == 1) {
+               *status |= FE_HAS_CARRIER;
+               *status |= FE_HAS_VITERBI;
+               *status |= FE_HAS_LOCK;
+               *status |= FE_HAS_SYNC;
+               *status |= FE_HAS_SIGNAL;
+       }
+
+       return 0;
+}
+
+static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber)
+{
+       dprintk("read ber\n");
+       return 0;
+}
+
+static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr)
+{
+       dprintk("read snr\n");
+       return 0;
+}
+
+static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
+{
+       dprintk("read ucblocks\n");
+       return 0;
+}
+
+static void s921_release(struct dvb_frontend *fe)
+{
+       struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops demod_s921={
+       .info = {
+               .name                   = "SHARP S921",
+               .type                   = FE_OFDM,
+               .frequency_min          = 473143000,
+               .frequency_max          = 767143000,
+               .frequency_stepsize     =   6000000,
+               .frequency_tolerance    = 0,
+               .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+                       FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+                       FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
+                       FE_CAN_MUTE_TS
+       },
+       .init = s921_init,
+       .sleep = s921_sleep,
+       .set_frontend = s921_set_parameters,
+       .read_snr = s921_read_snr,
+       .read_ber = s921_read_ber,
+       .read_status = s921_read_status,
+       .read_ucblocks = s921_read_ucblocks,
+       .release = s921_release,
+};
+
+static int s921_write(void *dev, u8 reg, u8 val) {
+       struct s921_state *state = dev;
+       char buf[2]={reg,val};
+       int err;
+       struct i2c_msg i2cmsgs = {
+               .addr = state->addr,
+               .flags = 0,
+               .len = 2,
+               .buf = buf
+       };
+
+       if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
+               printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
+               if (err < 0)
+                       return err;
+               else
+                       return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int s921_read(void *dev, u8 reg) {
+       struct s921_state *state = dev;
+       u8 b1;
+       int ret;
+       struct i2c_msg msg[2] = { { .addr = state->addr,
+                                   .flags = 0,
+                                   .buf = &reg, .len = 1 },
+                                 { .addr = state->addr,
+                                   .flags = I2C_M_RD,
+                                   .buf = &b1, .len = 1 } };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+       if (ret != 2)
+               return ret;
+       return b1;
+}
+
+struct dvb_frontend* s921_attach(const struct s921_config *config,
+                                          struct i2c_adapter *i2c)
+{
+
+       struct s921_state *state;
+       state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
+       memset(state, 0x0, sizeof(struct s921_state));
+
+       state->addr = config->i2c_address;
+       state->i2c = i2c;
+       state->dev.i2c_write = &s921_write;
+       state->dev.i2c_read = &s921_read;
+       state->dev.priv_dev = state;
+
+       s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL);
+
+       memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+}
+
+EXPORT_SYMBOL_GPL(s921_attach);
+MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
+MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s921_module.h b/drivers/media/dvb/frontends/s921_module.h
new file mode 100644 (file)
index 0000000..7866042
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  Driver for DVB-T s921 demodulator
+ *
+ *  Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
+ *
+ *  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 S921_MODULE_H
+#define S921_MODULE_H
+
+#include <linux/dvb/frontend.h>
+#include "s921_core.h"
+
+int s921_isdb_init(struct s921_isdb_t *dev);
+int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
+
+struct s921_config
+{
+       /* demodulator's I2C address */
+       u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) && defined(MODULE))
+extern struct dvb_frontend* s921_attach(const struct s921_config *config,
+                                          struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* s921_attach(const struct s921_config *config,
+                                          struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_S921 */
+
+#endif /* S921_H */
index 3ddbe69c45ce486673dbd3553ac07f0a579b7cc1..0bd16af8a6cd0723ab127f5a8de3c8d99e81e581 100644 (file)
@@ -8,7 +8,6 @@
 *      (at your option) any later version.
 *
 */
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c
new file mode 100644 (file)
index 0000000..ced9b7a
--- /dev/null
@@ -0,0 +1,1519 @@
+/*
+       STB0899 Multistandard 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 "stb0899_drv.h"
+#include "stb0899_priv.h"
+#include "stb0899_reg.h"
+
+inline u32 stb0899_do_div(u64 n, u32 d)
+{
+       /* wrap do_div() for ease of use */
+
+       do_div(n, d);
+       return n;
+}
+
+/*
+ * stb0899_calc_srate
+ * Compute symbol rate
+ */
+static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr)
+{
+       u64 tmp;
+
+       /* srate = (SFR * master_clk) >> 20 */
+
+       /* sfr is of size 20 bit, stored with an offset of 4 bit */
+       tmp = (((u32)sfr[0]) << 16) | (((u32)sfr[1]) << 8) | sfr[2];
+       tmp &= ~0xf;
+       tmp *= master_clk;
+       tmp >>= 24;
+
+       return tmp;
+}
+
+/*
+ * stb0899_get_srate
+ * Get the current symbol rate
+ */
+u32 stb0899_get_srate(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       u8 sfr[3];
+
+       stb0899_read_regs(state, STB0899_SFRH, sfr, 3);
+
+       return stb0899_calc_srate(internal->master_clk, sfr);
+}
+
+/*
+ * stb0899_set_srate
+ * Set symbol frequency
+ * MasterClock: master clock frequency (hz)
+ * SymbolRate: symbol rate (bauds)
+ * return symbol frequency
+ */
+static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 srate)
+{
+       u32 tmp;
+       u8 sfr[3];
+
+       dprintk(state->verbose, FE_DEBUG, 1, "-->");
+       /*
+        * in order to have the maximum precision, the symbol rate entered into
+        * the chip is computed as the closest value of the "true value".
+        * In this purpose, the symbol rate value is rounded (1 is added on the bit
+        * below the LSB )
+        *
+        * srate = (SFR * master_clk) >> 20
+        *      <=>
+        *   SFR = srate << 20 / master_clk
+        *
+        * rounded:
+        *   SFR = (srate << 21 + master_clk) / (2 * master_clk)
+        *
+        * stored as 20 bit number with an offset of 4 bit:
+        *   sfr = SFR << 4;
+        */
+
+       tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk);
+       tmp <<= 4;
+
+       sfr[0] = tmp >> 16;
+       sfr[1] = tmp >>  8;
+       sfr[2] = tmp;
+
+       stb0899_write_regs(state, STB0899_SFRH, sfr, 3);
+
+       return srate;
+}
+
+/*
+ * stb0899_calc_derot_time
+ * Compute the amount of time needed by the derotator to lock
+ * SymbolRate: Symbol rate
+ * return: derotator time constant (ms)
+ */
+static long stb0899_calc_derot_time(long srate)
+{
+       if (srate > 0)
+               return (100000 / (srate / 1000));
+       else
+               return 0;
+}
+
+/*
+ * stb0899_carr_width
+ * Compute the width of the carrier
+ * return: width of carrier (kHz or Mhz)
+ */
+long stb0899_carr_width(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+
+       return (internal->srate + (internal->srate * internal->rolloff) / 100);
+}
+
+/*
+ * stb0899_first_subrange
+ * Compute the first subrange of the search
+ */
+static void stb0899_first_subrange(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal       = &state->internal;
+       struct stb0899_params *params           = &state->params;
+       struct stb0899_config *config           =  state->config;
+
+       int range = 0;
+       u32 bandwidth = 0;
+
+       if (config->tuner_get_bandwidth) {
+               stb0899_i2c_gate_ctrl(&state->frontend, 1);
+               config->tuner_get_bandwidth(&state->frontend, &bandwidth);
+               stb0899_i2c_gate_ctrl(&state->frontend, 0);
+               range = bandwidth - stb0899_carr_width(state) / 2;
+       }
+
+       if (range > 0)
+               internal->sub_range = MIN(internal->srch_range, range);
+       else
+               internal->sub_range = 0;
+
+       internal->freq = params->freq;
+       internal->tuner_offst = 0L;
+       internal->sub_dir = 1;
+}
+
+/*
+ * stb0899_check_tmg
+ * check for timing lock
+ * internal.Ttiming: time to wait for loop lock
+ */
+static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       int lock;
+       u8 reg;
+       s8 timing;
+
+       msleep(internal->t_derot);
+
+       stb0899_write_reg(state, STB0899_RTF, 0xf2);
+       reg = stb0899_read_reg(state, STB0899_TLIR);
+       lock = STB0899_GETFIELD(TLIR_TMG_LOCK_IND, reg);
+       timing = stb0899_read_reg(state, STB0899_RTF);
+
+       if (lock >= 42) {
+               if ((lock > 48) && (ABS(timing) >= 110)) {
+                       internal->status = ANALOGCARRIER;
+                       dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !");
+               } else {
+                       internal->status = TIMINGOK;
+                       dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK !");
+               }
+       } else {
+               internal->status = NOTIMING;
+               dprintk(state->verbose, FE_DEBUG, 1, "-->NO TIMING !");
+       }
+       return internal->status;
+}
+
+/*
+ * stb0899_search_tmg
+ * perform a fs/2 zig-zag to find timing
+ */
+static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       short int derot_step, derot_freq = 0, derot_limit, next_loop = 3;
+       int index = 0;
+       u8 cfr[2];
+
+       internal->status = NOTIMING;
+
+       /* timing loop computation & symbol rate optimisation   */
+       derot_limit = (internal->sub_range / 2L) / internal->mclk;
+       derot_step = (params->srate / 2L) / internal->mclk;
+
+       while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) {
+               index++;
+               derot_freq += index * internal->direction * derot_step; /* next derot zig zag position  */
+
+               if (ABS(derot_freq) > derot_limit)
+                       next_loop--;
+
+               if (next_loop) {
+                       STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
+                       STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+                       stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency         */
+               }
+               internal->direction = -internal->direction;     /* Change zigzag direction              */
+       }
+
+       if (internal->status == TIMINGOK) {
+               stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency              */
+               internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+               dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq);
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_check_carrier
+ * Check for carrier found
+ */
+static enum stb0899_status stb0899_check_carrier(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       u8 reg;
+
+       msleep(internal->t_derot); /* wait for derotator ok     */
+
+       reg = stb0899_read_reg(state, STB0899_CFD);
+       STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+       stb0899_write_reg(state, STB0899_CFD, reg);
+
+       reg = stb0899_read_reg(state, STB0899_DSTATUS);
+       dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg);
+       if (STB0899_GETFIELD(CARRIER_FOUND, reg)) {
+               internal->status = CARRIEROK;
+               dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !");
+       } else {
+               internal->status = NOCARRIER;
+               dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !");
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_search_carrier
+ * Search for a QPSK carrier with the derotator
+ */
+static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+
+       short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3;
+       int index = 0;
+       u8 cfr[2];
+       u8 reg;
+
+       internal->status = NOCARRIER;
+       derot_limit = (internal->sub_range / 2L) / internal->mclk;
+       derot_freq = internal->derot_freq;
+
+       reg = stb0899_read_reg(state, STB0899_CFD);
+       STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+       stb0899_write_reg(state, STB0899_CFD, reg);
+
+       do {
+               dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk);
+               if (stb0899_check_carrier(state) == NOCARRIER) {
+                       index++;
+                       last_derot_freq = derot_freq;
+                       derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */
+
+                       if(ABS(derot_freq) > derot_limit)
+                               next_loop--;
+
+                       if (next_loop) {
+                               reg = stb0899_read_reg(state, STB0899_CFD);
+                               STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+                               stb0899_write_reg(state, STB0899_CFD, reg);
+
+                               STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
+                               STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+                               stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */
+                       }
+               }
+
+               internal->direction = -internal->direction; /* Change zigzag direction */
+       } while ((internal->status != CARRIEROK) && next_loop);
+
+       if (internal->status == CARRIEROK) {
+               stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
+               internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+               dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq);
+       } else {
+               internal->derot_freq = last_derot_freq;
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_check_data
+ * Check for data found
+ */
+static enum stb0899_status stb0899_check_data(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       int lock = 0, index = 0, dataTime = 500, loop;
+       u8 reg;
+
+       internal->status = NODATA;
+
+       /* RESET FEC    */
+       reg = stb0899_read_reg(state, STB0899_TSTRES);
+       STB0899_SETFIELD_VAL(FRESACS, reg, 1);
+       stb0899_write_reg(state, STB0899_TSTRES, reg);
+       msleep(1);
+       reg = stb0899_read_reg(state, STB0899_TSTRES);
+       STB0899_SETFIELD_VAL(FRESACS, reg, 0);
+       stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+       if (params->srate <= 2000000)
+               dataTime = 2000;
+       else if (params->srate <= 5000000)
+               dataTime = 1500;
+       else if (params->srate <= 15000000)
+               dataTime = 1000;
+       else
+               dataTime = 500;
+
+       stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop  */
+       while (1) {
+               /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP    */
+               reg = stb0899_read_reg(state, STB0899_VSTATUS);
+               lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg);
+               loop = STB0899_GETFIELD(VSTATUS_END_LOOPVIT, reg);
+
+               if (lock || loop || (index > dataTime))
+                       break;
+               index++;
+       }
+
+       if (lock) {     /* DATA LOCK indicator  */
+               internal->status = DATAOK;
+               dprintk(state->verbose, FE_DEBUG, 1, "-----------------> DATA OK !");
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_search_data
+ * Search for a QPSK carrier with the derotator
+ */
+static enum stb0899_status stb0899_search_data(struct stb0899_state *state)
+{
+       short int derot_freq, derot_step, derot_limit, next_loop = 3;
+       u8 cfr[2];
+       u8 reg;
+       int index = 1;
+
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       derot_step = (params->srate / 4L) / internal->mclk;
+       derot_limit = (internal->sub_range / 2L) / internal->mclk;
+       derot_freq = internal->derot_freq;
+
+       do {
+               if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) {
+
+                       derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */
+                       if (ABS(derot_freq) > derot_limit)
+                               next_loop--;
+
+                       if (next_loop) {
+                               dprintk(state->verbose, FE_DEBUG, 1, "Derot freq=%d, mclk=%d", derot_freq, internal->mclk);
+                               reg = stb0899_read_reg(state, STB0899_CFD);
+                               STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+                               stb0899_write_reg(state, STB0899_CFD, reg);
+
+                               STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
+                               STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+                               stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */
+
+                               stb0899_check_carrier(state);
+                               index++;
+                       }
+               }
+               internal->direction = -internal->direction; /* change zig zag direction */
+       } while ((internal->status != DATAOK) && next_loop);
+
+       if (internal->status == DATAOK) {
+               stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
+               internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+               dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq);
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_check_range
+ * check if the found frequency is in the correct range
+ */
+static enum stb0899_status stb0899_check_range(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       int range_offst, tp_freq;
+
+       range_offst = internal->srch_range / 2000;
+       tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000;
+
+       if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) {
+               internal->status = RANGEOK;
+               dprintk(state->verbose, FE_DEBUG, 1, "----> RANGEOK !");
+       } else {
+               internal->status = OUTOFRANGE;
+               dprintk(state->verbose, FE_DEBUG, 1, "----> OUT OF RANGE !");
+       }
+
+       return internal->status;
+}
+
+/*
+ * NextSubRange
+ * Compute the next subrange of the search
+ */
+static void next_sub_range(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       long old_sub_range;
+
+       if (internal->sub_dir > 0) {
+               old_sub_range = internal->sub_range;
+               internal->sub_range = MIN((internal->srch_range / 2) -
+                                         (internal->tuner_offst + internal->sub_range / 2),
+                                          internal->sub_range);
+
+               if (internal->sub_range < 0)
+                       internal->sub_range = 0;
+
+               internal->tuner_offst += (old_sub_range + internal->sub_range) / 2;
+       }
+
+       internal->freq = params->freq + (internal->sub_dir * internal->tuner_offst) / 1000;
+       internal->sub_dir = -internal->sub_dir;
+}
+
+/*
+ * stb0899_dvbs_algo
+ * Search for a signal, timing, carrier and data for a
+ * given frequency in a given range
+ */
+enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state)
+{
+       struct stb0899_params *params           = &state->params;
+       struct stb0899_internal *internal       = &state->internal;
+       struct stb0899_config *config           = state->config;
+
+       u8 bclc, reg;
+       u8 cfr[2];
+       u8 eq_const[10];
+       s32 clnI = 3;
+       u32 bandwidth = 0;
+
+       /* BETA values rated @ 99MHz    */
+       s32 betaTab[5][4] = {
+              /*  5   10   20   30MBps */
+               { 37,  34,  32,  31 }, /* QPSK 1/2      */
+               { 37,  35,  33,  31 }, /* QPSK 2/3      */
+               { 37,  35,  33,  31 }, /* QPSK 3/4      */
+               { 37,  36,  33,  32 }, /* QPSK 5/6      */
+               { 37,  36,  33,  32 }  /* QPSK 7/8      */
+       };
+
+       internal->direction = 1;
+
+       stb0899_set_srate(state, internal->master_clk, params->srate);
+       /* Carrier loop optimization versus symbol rate for acquisition*/
+       if (params->srate <= 5000000) {
+               stb0899_write_reg(state, STB0899_ACLC, 0x89);
+               bclc = stb0899_read_reg(state, STB0899_BCLC);
+               STB0899_SETFIELD_VAL(BETA, bclc, 0x1c);
+               stb0899_write_reg(state, STB0899_BCLC, bclc);
+               clnI = 0;
+       } else if (params->srate <= 15000000) {
+               stb0899_write_reg(state, STB0899_ACLC, 0xc9);
+               bclc = stb0899_read_reg(state, STB0899_BCLC);
+               STB0899_SETFIELD_VAL(BETA, bclc, 0x22);
+               stb0899_write_reg(state, STB0899_BCLC, bclc);
+               clnI = 1;
+       } else if(params->srate <= 25000000) {
+               stb0899_write_reg(state, STB0899_ACLC, 0x89);
+               bclc = stb0899_read_reg(state, STB0899_BCLC);
+               STB0899_SETFIELD_VAL(BETA, bclc, 0x27);
+               stb0899_write_reg(state, STB0899_BCLC, bclc);
+               clnI = 2;
+       } else {
+               stb0899_write_reg(state, STB0899_ACLC, 0xc8);
+               bclc = stb0899_read_reg(state, STB0899_BCLC);
+               STB0899_SETFIELD_VAL(BETA, bclc, 0x29);
+               stb0899_write_reg(state, STB0899_BCLC, bclc);
+               clnI = 3;
+       }
+
+       dprintk(state->verbose, FE_DEBUG, 1, "Set the timing loop to acquisition");
+       /* Set the timing loop to acquisition   */
+       stb0899_write_reg(state, STB0899_RTC, 0x46);
+       stb0899_write_reg(state, STB0899_CFD, 0xee);
+
+       /* !! WARNING !!
+        * Do not read any status variables while acquisition,
+        * If any needed, read before the acquisition starts
+        * querying status while acquiring causes the
+        * acquisition to go bad and hence no locks.
+        */
+       dprintk(state->verbose, FE_DEBUG, 1, "Derot Percent=%d Srate=%d mclk=%d",
+               internal->derot_percent, params->srate, internal->mclk);
+
+       /* Initial calculations */
+       internal->derot_step = internal->derot_percent * (params->srate / 1000L) / internal->mclk; /* DerotStep/1000 * Fsymbol  */
+       internal->t_derot = stb0899_calc_derot_time(params->srate);
+       internal->t_data = 500;
+
+       dprintk(state->verbose, FE_DEBUG, 1, "RESET stream merger");
+       /* RESET Stream merger  */
+       reg = stb0899_read_reg(state, STB0899_TSTRES);
+       STB0899_SETFIELD_VAL(FRESRS, reg, 1);
+       stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+       /*
+        * Set KDIVIDER to an intermediate value between
+        * 1/2 and 7/8 for acquisition
+        */
+       reg = stb0899_read_reg(state, STB0899_DEMAPVIT);
+       STB0899_SETFIELD_VAL(DEMAPVIT_KDIVIDER, reg, 60);
+       stb0899_write_reg(state, STB0899_DEMAPVIT, reg);
+
+       stb0899_write_reg(state, STB0899_EQON, 0x01); /* Equalizer OFF while acquiring */
+       stb0899_write_reg(state, STB0899_VITSYNC, 0x19);
+
+       stb0899_first_subrange(state);
+       do {
+               /* Initialisations */
+               cfr[0] = cfr[1] = 0;
+               stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* RESET derotator frequency   */
+
+               stb0899_write_reg(state, STB0899_RTF, 0);
+               reg = stb0899_read_reg(state, STB0899_CFD);
+               STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+               stb0899_write_reg(state, STB0899_CFD, reg);
+
+               internal->derot_freq = 0;
+               internal->status = NOAGC1;
+
+               /* enable tuner I/O */
+               stb0899_i2c_gate_ctrl(&state->frontend, 1);
+
+               /* Move tuner to frequency */
+               dprintk(state->verbose, FE_DEBUG, 1, "Tuner set frequency");
+               if (state->config->tuner_set_frequency)
+                       state->config->tuner_set_frequency(&state->frontend, internal->freq);
+
+               if (state->config->tuner_get_frequency)
+                       state->config->tuner_get_frequency(&state->frontend, &internal->freq);
+
+               msleep(internal->t_agc1 + internal->t_agc2 + internal->t_derot); /* AGC1, AGC2 and timing loop  */
+               dprintk(state->verbose, FE_DEBUG, 1, "current derot freq=%d", internal->derot_freq);
+               internal->status = AGC1OK;
+
+               /* There is signal in the band  */
+               if (config->tuner_get_bandwidth)
+                       config->tuner_get_bandwidth(&state->frontend, &bandwidth);
+
+               /* disable tuner I/O */
+               stb0899_i2c_gate_ctrl(&state->frontend, 0);
+
+               if (params->srate <= bandwidth / 2)
+                       stb0899_search_tmg(state); /* For low rates (SCPC)      */
+               else
+                       stb0899_check_tmg(state); /* For high rates (MCPC)      */
+
+               if (internal->status == TIMINGOK) {
+                       dprintk(state->verbose, FE_DEBUG, 1,
+                               "TIMING OK ! Derot freq=%d, mclk=%d",
+                               internal->derot_freq, internal->mclk);
+
+                       if (stb0899_search_carrier(state) == CARRIEROK) {       /* Search for carrier   */
+                               dprintk(state->verbose, FE_DEBUG, 1,
+                                       "CARRIER OK ! Derot freq=%d, mclk=%d",
+                                       internal->derot_freq, internal->mclk);
+
+                               if (stb0899_search_data(state) == DATAOK) {     /* Check for data       */
+                                       dprintk(state->verbose, FE_DEBUG, 1,
+                                               "DATA OK ! Derot freq=%d, mclk=%d",
+                                               internal->derot_freq, internal->mclk);
+
+                                       if (stb0899_check_range(state) == RANGEOK) {
+                                               dprintk(state->verbose, FE_DEBUG, 1,
+                                                       "RANGE OK ! derot freq=%d, mclk=%d",
+                                                       internal->derot_freq, internal->mclk);
+
+                                               internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000);
+                                               reg = stb0899_read_reg(state, STB0899_PLPARM);
+                                               internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg);
+                                               dprintk(state->verbose, FE_DEBUG, 1,
+                                                       "freq=%d, internal resultant freq=%d",
+                                                       params->freq, internal->freq);
+
+                                               dprintk(state->verbose, FE_DEBUG, 1,
+                                                       "internal puncture rate=%d",
+                                                       internal->fecrate);
+                                       }
+                               }
+                       }
+               }
+               if (internal->status != RANGEOK)
+                       next_sub_range(state);
+
+       } while (internal->sub_range && internal->status != RANGEOK);
+
+       /* Set the timing loop to tracking      */
+       stb0899_write_reg(state, STB0899_RTC, 0x33);
+       stb0899_write_reg(state, STB0899_CFD, 0xf7);
+       /* if locked and range ok, set Kdiv     */
+       if (internal->status == RANGEOK) {
+               dprintk(state->verbose, FE_DEBUG, 1, "Locked & Range OK !");
+               stb0899_write_reg(state, STB0899_EQON, 0x41);           /* Equalizer OFF while acquiring        */
+               stb0899_write_reg(state, STB0899_VITSYNC, 0x39);        /* SN to b'11 for acquisition           */
+
+               /*
+                * Carrier loop optimization versus
+                * symbol Rate/Puncture Rate for Tracking
+                */
+               reg = stb0899_read_reg(state, STB0899_BCLC);
+               switch (internal->fecrate) {
+               case STB0899_FEC_1_2:           /* 13   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 0x1a);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[0][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               case STB0899_FEC_2_3:           /* 18   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 44);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[1][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               case STB0899_FEC_3_4:           /* 21   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 60);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[2][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               case STB0899_FEC_5_6:           /* 24   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 75);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[3][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               case STB0899_FEC_6_7:           /* 25   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 88);
+                       stb0899_write_reg(state, STB0899_ACLC, 0x88);
+                       stb0899_write_reg(state, STB0899_BCLC, 0x9a);
+                       break;
+               case STB0899_FEC_7_8:           /* 26   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 94);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[4][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               default:
+                       dprintk(state->verbose, FE_DEBUG, 1, "Unsupported Puncture Rate");
+                       break;
+               }
+               /* release stream merger RESET  */
+               reg = stb0899_read_reg(state, STB0899_TSTRES);
+               STB0899_SETFIELD_VAL(FRESRS, reg, 0);
+               stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+               /* disable carrier detector     */
+               reg = stb0899_read_reg(state, STB0899_CFD);
+               STB0899_SETFIELD_VAL(CFD_ON, reg, 0);
+               stb0899_write_reg(state, STB0899_CFD, reg);
+
+               stb0899_read_regs(state, STB0899_EQUAI1, eq_const, 10);
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_dvbs2_config_uwp
+ * Configure UWP state machine
+ */
+static void stb0899_dvbs2_config_uwp(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_config *config = state->config;
+       u32 uwp1, uwp2, uwp3, reg;
+
+       uwp1 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1);
+       uwp2 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL2);
+       uwp3 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL3);
+
+       STB0899_SETFIELD_VAL(UWP_ESN0_AVE, uwp1, config->esno_ave);
+       STB0899_SETFIELD_VAL(UWP_ESN0_QUANT, uwp1, config->esno_quant);
+       STB0899_SETFIELD_VAL(UWP_TH_SOF, uwp1, config->uwp_threshold_sof);
+
+       STB0899_SETFIELD_VAL(FE_COARSE_TRK, uwp2, internal->av_frame_coarse);
+       STB0899_SETFIELD_VAL(FE_FINE_TRK, uwp2, internal->av_frame_fine);
+       STB0899_SETFIELD_VAL(UWP_MISS_TH, uwp2, config->miss_threshold);
+
+       STB0899_SETFIELD_VAL(UWP_TH_ACQ, uwp3, config->uwp_threshold_acq);
+       STB0899_SETFIELD_VAL(UWP_TH_TRACK, uwp3, config->uwp_threshold_track);
+
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL1, STB0899_OFF0_UWP_CNTRL1, uwp1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL2, STB0899_OFF0_UWP_CNTRL2, uwp2);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL3, STB0899_OFF0_UWP_CNTRL3, uwp3);
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, SOF_SRCH_TO);
+       STB0899_SETFIELD_VAL(SOF_SEARCH_TIMEOUT, reg, config->sof_search_timeout);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_SOF_SRCH_TO, STB0899_OFF0_SOF_SRCH_TO, reg);
+}
+
+/*
+ * stb0899_dvbs2_config_csm_auto
+ * Set CSM to AUTO mode
+ */
+static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state)
+{
+       u32 reg;
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+       STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, reg, 1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg);
+}
+
+long Log2Int(int number)
+{
+       int i;
+
+       i = 0;
+       while ((1 << i) <= ABS(number))
+               i++;
+
+       if (number == 0)
+               i = 1;
+
+       return i - 1;
+}
+
+/*
+ * stb0899_dvbs2_calc_srate
+ * compute BTR_NOM_FREQ for the symbol rate
+ */
+static u32 stb0899_dvbs2_calc_srate(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal       = &state->internal;
+       struct stb0899_config *config           = state->config;
+
+       u32 dec_ratio, dec_rate, decim, remain, intval, btr_nom_freq;
+       u32 master_clk, srate;
+
+       dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+       dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+       dec_rate = Log2Int(dec_ratio);
+       decim = 1 << dec_rate;
+       master_clk = internal->master_clk / 1000;
+       srate = internal->srate / 1000;
+
+       if (decim <= 4) {
+               intval = (decim * (1 << (config->btr_nco_bits - 1))) / master_clk;
+               remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
+       } else {
+               intval = (1 << (config->btr_nco_bits - 1)) / (master_clk / 100) * decim / 100;
+               remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
+       }
+       btr_nom_freq = (intval * srate) + ((remain * srate) / master_clk);
+
+       return btr_nom_freq;
+}
+
+/*
+ * stb0899_dvbs2_calc_dev
+ * compute the correction to be applied to symbol rate
+ */
+static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       u32 dec_ratio, correction, master_clk, srate;
+
+       dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+       dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+
+       master_clk = internal->master_clk / 1000;       /* for integer Caculation*/
+       srate = internal->srate / 1000; /* for integer Caculation*/
+       correction = (512 * master_clk) / (2 * dec_ratio * srate);
+
+       return  correction;
+}
+
+/*
+ * stb0899_dvbs2_set_srate
+ * Set DVBS2 symbol rate
+ */
+static void stb0899_dvbs2_set_srate(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+
+       u32 dec_ratio, dec_rate, win_sel, decim, f_sym, btr_nom_freq;
+       u32 correction, freq_adj, band_lim, decim_cntrl, reg;
+       u8 anti_alias;
+
+       /*set decimation to 1*/
+       dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+       dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+       dec_rate = Log2Int(dec_ratio);
+
+       win_sel = 0;
+       if (dec_rate >= 5)
+               win_sel = dec_rate - 4;
+
+       decim = (1 << dec_rate);
+       /* (FSamp/Fsymbol *100) for integer Caculation */
+       f_sym = internal->master_clk / ((decim * internal->srate) / 1000);
+
+       if (f_sym <= 2250)      /* don't band limit signal going into btr block*/
+               band_lim = 1;
+       else
+               band_lim = 0;   /* band limit signal going into btr block*/
+
+       decim_cntrl = ((win_sel << 3) & 0x18) + ((band_lim << 5) & 0x20) + (dec_rate & 0x7);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DECIM_CNTRL, STB0899_OFF0_DECIM_CNTRL, decim_cntrl);
+
+       if (f_sym <= 3450)
+               anti_alias = 0;
+       else if (f_sym <= 4250)
+               anti_alias = 1;
+       else
+               anti_alias = 2;
+
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ANTI_ALIAS_SEL, STB0899_OFF0_ANTI_ALIAS_SEL, anti_alias);
+       btr_nom_freq = stb0899_dvbs2_calc_srate(state);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_NOM_FREQ, STB0899_OFF0_BTR_NOM_FREQ, btr_nom_freq);
+
+       correction = stb0899_dvbs2_calc_dev(state);
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
+       STB0899_SETFIELD_VAL(BTR_FREQ_CORR, reg, correction);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
+
+       /* scale UWP+CSM frequency to sample rate*/
+       freq_adj =  internal->srate / (internal->master_clk / 4096);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_FREQ_ADJ_SCALE, STB0899_OFF0_FREQ_ADJ_SCALE, freq_adj);
+}
+
+/*
+ * stb0899_dvbs2_set_btr_loopbw
+ * set bit timing loop bandwidth as a percentage of the symbol rate
+ */
+static void stb0899_dvbs2_set_btr_loopbw(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal       = &state->internal;
+       struct stb0899_config *config           = state->config;
+
+       u32 sym_peak = 23, zeta = 707, loopbw_percent = 60;
+       s32 dec_ratio, dec_rate, k_btr1_rshft, k_btr1, k_btr0_rshft;
+       s32 k_btr0, k_btr2_rshft, k_direct_shift, k_indirect_shift;
+       u32 decim, K, wn, k_direct, k_indirect;
+       u32 reg;
+
+       dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+       dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+       dec_rate = Log2Int(dec_ratio);
+       decim = (1 << dec_rate);
+
+       sym_peak *= 576000;
+       K = (1 << config->btr_nco_bits) / (internal->master_clk / 1000);
+       K *= (internal->srate / 1000000) * decim; /*k=k 10^-8*/
+
+       if (K != 0) {
+               K = sym_peak / K;
+               wn = (4 * zeta * zeta) + 1000000;
+               wn = (2 * (loopbw_percent * 1000) * 40 * zeta) /wn;  /*wn =wn 10^-8*/
+
+               k_indirect = (wn * wn) / K;
+               k_indirect = k_indirect;          /*kindirect = kindirect 10^-6*/
+               k_direct   = (2 * wn * zeta) / K;       /*kDirect = kDirect 10^-2*/
+               k_direct  *= 100;
+
+               k_direct_shift = Log2Int(k_direct) - Log2Int(10000) - 2;
+               k_btr1_rshft = (-1 * k_direct_shift) + config->btr_gain_shift_offset;
+               k_btr1 = k_direct / (1 << k_direct_shift);
+               k_btr1 /= 10000;
+
+               k_indirect_shift = Log2Int(k_indirect + 15) - 20 /*- 2*/;
+               k_btr0_rshft = (-1 * k_indirect_shift) + config->btr_gain_shift_offset;
+               k_btr0 = k_indirect * (1 << (-k_indirect_shift));
+               k_btr0 /= 1000000;
+
+               k_btr2_rshft = 0;
+               if (k_btr0_rshft > 15) {
+                       k_btr2_rshft = k_btr0_rshft - 15;
+                       k_btr0_rshft = 15;
+               }
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_LOOP_GAIN);
+               STB0899_SETFIELD_VAL(KBTR0_RSHFT, reg, k_btr0_rshft);
+               STB0899_SETFIELD_VAL(KBTR0, reg, k_btr0);
+               STB0899_SETFIELD_VAL(KBTR1_RSHFT, reg, k_btr1_rshft);
+               STB0899_SETFIELD_VAL(KBTR1, reg, k_btr1);
+               STB0899_SETFIELD_VAL(KBTR2_RSHFT, reg, k_btr2_rshft);
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, reg);
+       } else
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, 0xc4c4f);
+}
+
+/*
+ * stb0899_dvbs2_set_carr_freq
+ * set nominal frequency for carrier search
+ */
+static void stb0899_dvbs2_set_carr_freq(struct stb0899_state *state, s32 carr_freq, u32 master_clk)
+{
+       struct stb0899_config *config = state->config;
+       s32 crl_nom_freq;
+       u32 reg;
+
+       crl_nom_freq = (1 << config->crl_nco_bits) / master_clk;
+       crl_nom_freq *= carr_freq;
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
+       STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, crl_nom_freq);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
+}
+
+/*
+ * stb0899_dvbs2_init_calc
+ * Initialize DVBS2 UWP, CSM, carrier and timing loops
+ */
+static void stb0899_dvbs2_init_calc(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       s32 steps, step_size;
+       u32 range, reg;
+
+       /* config uwp and csm */
+       stb0899_dvbs2_config_uwp(state);
+       stb0899_dvbs2_config_csm_auto(state);
+
+       /* initialize BTR       */
+       stb0899_dvbs2_set_srate(state);
+       stb0899_dvbs2_set_btr_loopbw(state);
+
+       if (internal->srate / 1000000 >= 15)
+               step_size = (1 << 17) / 5;
+       else if (internal->srate / 1000000 >= 10)
+               step_size = (1 << 17) / 7;
+       else if (internal->srate / 1000000 >= 5)
+               step_size = (1 << 17) / 10;
+       else
+               step_size = (1 << 17) / 4;
+
+       range = internal->srch_range / 1000000;
+       steps = (10 * range * (1 << 17)) / (step_size * (internal->srate / 1000000));
+       steps = (steps + 6) / 10;
+       steps = (steps == 0) ? 1 : steps;
+       if (steps % 2 == 0)
+               stb0899_dvbs2_set_carr_freq(state, internal->center_freq -
+                                          (internal->step_size * (internal->srate / 20000000)),
+                                          (internal->master_clk) / 1000000);
+       else
+               stb0899_dvbs2_set_carr_freq(state, internal->center_freq, (internal->master_clk) / 1000000);
+
+       /*Set Carrier Search params (zigzag, num steps and freq step size*/
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, ACQ_CNTRL2);
+       STB0899_SETFIELD_VAL(ZIGZAG, reg, 1);
+       STB0899_SETFIELD_VAL(NUM_STEPS, reg, steps);
+       STB0899_SETFIELD_VAL(FREQ_STEPSIZE, reg, step_size);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQ_CNTRL2, STB0899_OFF0_ACQ_CNTRL2, reg);
+}
+
+/*
+ * stb0899_dvbs2_btr_init
+ * initialize the timing loop
+ */
+static void stb0899_dvbs2_btr_init(struct stb0899_state *state)
+{
+       u32 reg;
+
+       /* set enable BTR loopback      */
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
+       STB0899_SETFIELD_VAL(INTRP_PHS_SENSE, reg, 1);
+       STB0899_SETFIELD_VAL(BTR_ERR_ENA, reg, 1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
+
+       /* fix btr freq accum at 0      */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x10000000);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x00000000);
+
+       /* fix btr freq accum at 0      */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x10000000);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x00000000);
+}
+
+/*
+ * stb0899_dvbs2_reacquire
+ * trigger a DVB-S2 acquisition
+ */
+static void stb0899_dvbs2_reacquire(struct stb0899_state *state)
+{
+       u32 reg = 0;
+
+       /* demod soft reset     */
+       STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
+
+       /*Reset Timing Loop     */
+       stb0899_dvbs2_btr_init(state);
+
+       /* reset Carrier loop   */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, (1 << 30));
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, 0);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_LOOP_GAIN, STB0899_OFF0_CRL_LOOP_GAIN, 0);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, (1 << 30));
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, 0);
+
+       /*release demod soft reset      */
+       reg = 0;
+       STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 0);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
+
+       /* start acquisition process    */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQUIRE_TRIG, STB0899_OFF0_ACQUIRE_TRIG, 1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_LOCK_LOST, STB0899_OFF0_LOCK_LOST, 0);
+
+       /* equalizer Init       */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 1);
+
+       /*Start equilizer       */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 0);
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
+       STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0);
+       STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 0);
+       STB0899_SETFIELD_VAL(EQ_DELAY, reg, 0x05);
+       STB0899_SETFIELD_VAL(EQ_ADAPT_MODE, reg, 0x01);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
+
+       /* RESET Packet delineator      */
+       stb0899_write_reg(state, STB0899_PDELCTRL, 0x4a);
+}
+
+/*
+ * stb0899_dvbs2_get_dmd_status
+ * get DVB-S2 Demod LOCK status
+ */
+static enum stb0899_status stb0899_dvbs2_get_dmd_status(struct stb0899_state *state, int timeout)
+{
+       int time = -10, lock = 0, uwp, csm;
+       u32 reg;
+
+       do {
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS);
+               dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg);
+               if (STB0899_GETFIELD(IF_AGC_LOCK, reg))
+                       dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !");
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2);
+               dprintk(state->verbose, FE_DEBUG, 1, "----------->DMD STAT2=[0x%02x]", reg);
+               uwp = STB0899_GETFIELD(UWP_LOCK, reg);
+               csm = STB0899_GETFIELD(CSM_LOCK, reg);
+               if (uwp && csm)
+                       lock = 1;
+
+               time += 10;
+               msleep(10);
+
+       } while ((!lock) && (time <= timeout));
+
+       if (lock) {
+               dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 LOCK !");
+               return DVBS2_DEMOD_LOCK;
+       } else {
+               return DVBS2_DEMOD_NOLOCK;
+       }
+}
+
+/*
+ * stb0899_dvbs2_get_data_lock
+ * get FEC status
+ */
+static int stb0899_dvbs2_get_data_lock(struct stb0899_state *state, int timeout)
+{
+       int time = 0, lock = 0;
+       u8 reg;
+
+       while ((!lock) && (time < timeout)) {
+               reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1);
+               dprintk(state->verbose, FE_DEBUG, 1, "---------> CFGPDELSTATUS=[0x%02x]", reg);
+               lock = STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg);
+               time++;
+       }
+
+       return lock;
+}
+
+/*
+ * stb0899_dvbs2_get_fec_status
+ * get DVB-S2 FEC LOCK status
+ */
+static enum stb0899_status stb0899_dvbs2_get_fec_status(struct stb0899_state *state, int timeout)
+{
+       int time = 0, Locked;
+
+       do {
+               Locked = stb0899_dvbs2_get_data_lock(state, 1);
+               time++;
+               msleep(1);
+
+       } while ((!Locked) && (time < timeout));
+
+       if (Locked) {
+               dprintk(state->verbose, FE_DEBUG, 1, "---------->DVB-S2 FEC LOCK !");
+               return DVBS2_FEC_LOCK;
+       } else {
+               return DVBS2_FEC_NOLOCK;
+       }
+}
+
+
+/*
+ * stb0899_dvbs2_init_csm
+ * set parameters for manual mode
+ */
+static void stb0899_dvbs2_init_csm(struct stb0899_state *state, int pilots, enum stb0899_modcod modcod)
+{
+       struct stb0899_internal *internal = &state->internal;
+
+       s32 dvt_tbl = 1, two_pass = 0, agc_gain = 6, agc_shift = 0, loop_shift = 0, phs_diff_thr = 0x80;
+       s32 gamma_acq, gamma_rho_acq, gamma_trk, gamma_rho_trk, lock_count_thr;
+       u32 csm1, csm2, csm3, csm4;
+
+       if (((internal->master_clk / internal->srate) <= 4) && (modcod <= 11) && (pilots == 1)) {
+               switch (modcod) {
+               case STB0899_QPSK_12:
+                       gamma_acq               = 25;
+                       gamma_rho_acq           = 2700;
+                       gamma_trk               = 12;
+                       gamma_rho_trk           = 180;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_35:
+                       gamma_acq               = 38;
+                       gamma_rho_acq           = 7182;
+                       gamma_trk               = 14;
+                       gamma_rho_trk           = 308;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_23:
+                       gamma_acq               = 42;
+                       gamma_rho_acq           = 9408;
+                       gamma_trk               = 17;
+                       gamma_rho_trk           = 476;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_34:
+                       gamma_acq               = 53;
+                       gamma_rho_acq           = 16642;
+                       gamma_trk               = 19;
+                       gamma_rho_trk           = 646;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_45:
+                       gamma_acq               = 53;
+                       gamma_rho_acq           = 17119;
+                       gamma_trk               = 22;
+                       gamma_rho_trk           = 880;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_56:
+                       gamma_acq               = 55;
+                       gamma_rho_acq           = 19250;
+                       gamma_trk               = 23;
+                       gamma_rho_trk           = 989;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_89:
+                       gamma_acq               = 60;
+                       gamma_rho_acq           = 24240;
+                       gamma_trk               = 24;
+                       gamma_rho_trk           = 1176;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_910:
+                       gamma_acq               = 66;
+                       gamma_rho_acq           = 29634;
+                       gamma_trk               = 24;
+                       gamma_rho_trk           = 1176;
+                       lock_count_thr          = 8;
+                       break;
+               default:
+  &n