Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
Linus Torvalds [Mon, 13 Oct 2008 21:03:59 +0000 (14:03 -0700)]
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (313 commits)
  V4L/DVB (9186): Added support for Prof 7300 DVB-S/S2 cards
  V4L/DVB (9185): S2API: Ensure we have a reasonable ROLLOFF default
  V4L/DVB (9184): cx24116: Change the default SNR units back to percentage by default.
  V4L/DVB (9183): S2API: Return error of the caller provides 0 commands.
  V4L/DVB (9182): S2API: Added support for DTV_HIERARCHY
  V4L/DVB (9181): S2API: Add support fot DTV_GUARD_INTERVAL and DTV_TRANSMISSION_MODE
  V4L/DVB (9180): S2API: Added support for DTV_CODE_RATE_HP/LP
  V4L/DVB (9179): S2API: frontend.h cleanup
  V4L/DVB (9178): cx24116: Add module parameter to return SNR as ESNO.
  V4L/DVB (9177): S2API: Change _8PSK / _16APSK to PSK_8 and APSK_16
  V4L/DVB (9176): Add support for DvbWorld USB cards with STV0288 demodulator.
  V4L/DVB (9175): Remove NULL pointer in stb6000 driver.
  V4L/DVB (9174): Allow custom inittab for ST STV0288 demodulator.
  V4L/DVB (9173): S2API: Remove the hardcoded command limit during validation
  V4L/DVB (9172): S2API: Bugfix related to DVB-S / DVB-S2 tuning for the legacy API.
  V4L/DVB (9171): S2API: Stop an OOPS if illegal commands are dumped in S2API.
  V4L/DVB (9170): cx24116: Sanity checking to data input via S2API to the cx24116 demod.
  V4L/DVB (9169): uvcvideo: Support two new Bison Electronics webcams.
  V4L/DVB (9168): Add support for MSI TV@nywhere Plus remote
  V4L/DVB: v4l2-dev: remove duplicated #include
  ...

377 files changed:
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/gspca.txt
Documentation/video4linux/m5602.txt [new file with mode: 0644]
Documentation/video4linux/soc-camera.txt [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/camera.h
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_fops.c
drivers/media/common/tuners/mt2060.c
drivers/media/common/tuners/mxl5007t.c
drivers/media/common/tuners/tda18271-fe.c
drivers/media/common/tuners/tda827x.c
drivers/media/common/tuners/tda827x.h
drivers/media/common/tuners/tda8290.c
drivers/media/common/tuners/tda8290.h
drivers/media/common/tuners/tda9887.c
drivers/media/common/tuners/tuner-simple.c
drivers/media/common/tuners/tuner-types.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/tuner-xc2028.h
drivers/media/common/tuners/xc5000.c
drivers/media/common/tuners/xc5000.h
drivers/media/common/tuners/xc5000_priv.h [deleted file]
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/b2c2/flexcop-dma.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/cinergyT2/Kconfig [deleted file]
drivers/media/dvb/cinergyT2/Makefile [deleted file]
drivers/media/dvb/cinergyT2/cinergyT2.c [deleted file]
drivers/media/dvb/dm1105/Kconfig [new file with mode: 0644]
drivers/media/dvb/dm1105/Makefile [new file with mode: 0644]
drivers/media/dvb/dm1105/dm1105.c [new file with mode: 0644]
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/af9005-remote.c
drivers/media/dvb/dvb-usb/af9005-script.h
drivers/media/dvb/dvb-usb/af9005.c
drivers/media/dvb/dvb-usb/af9015.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/af9015.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/cinergyT2-core.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/cinergyT2-fe.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/cinergyT2.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dib0700.h
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dtv5100.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dtv5100.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/dw2102.h
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/af9013.c [new file with mode: 0644]
drivers/media/dvb/frontends/af9013.h [new file with mode: 0644]
drivers/media/dvb/frontends/af9013_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/au8522.c
drivers/media/dvb/frontends/au8522.h
drivers/media/dvb/frontends/cx24110.h
drivers/media/dvb/frontends/cx24116.c [new file with mode: 0644]
drivers/media/dvb/frontends/cx24116.h [new file with mode: 0644]
drivers/media/dvb/frontends/dib0070.h
drivers/media/dvb/frontends/dib7000m.c
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/dib7000p.h
drivers/media/dvb/frontends/drx397xD.c
drivers/media/dvb/frontends/drx397xD.h
drivers/media/dvb/frontends/dvb_dummy_fe.c
drivers/media/dvb/frontends/eds1547.h [new file with mode: 0644]
drivers/media/dvb/frontends/lgs8gl5.c [new file with mode: 0644]
drivers/media/dvb/frontends/lgs8gl5.h [new file with mode: 0644]
drivers/media/dvb/frontends/nxt200x.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/si21xx.c [new file with mode: 0644]
drivers/media/dvb/frontends/si21xx.h [new file with mode: 0644]
drivers/media/dvb/frontends/sp887x.c
drivers/media/dvb/frontends/stb6000.c [new file with mode: 0644]
drivers/media/dvb/frontends/stb6000.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0288.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv0288.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/stv0299.h
drivers/media/dvb/frontends/tdhd1.h [new file with mode: 0644]
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget-core.c
drivers/media/dvb/ttpci/budget-patch.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttpci/budget.h
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/dvb/ttusb-dec/ttusb_dec.c
drivers/media/dvb/ttusb-dec/ttusbdecfe.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maestro.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-mr800.c [new file with mode: 0644]
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-si470x.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-dvb.c
drivers/media/video/au0828/au0828.h
drivers/media/video/bt856.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/btcx-risc.c
drivers/media/video/bw-qcam.c
drivers/media/video/bw-qcam.h
drivers/media/video/c-qcam.c
drivers/media/video/cafe_ccic.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/cx18/Makefile
drivers/media/video/cx18/cx18-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-cards.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-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 [new file with mode: 0644]
drivers/media/video/cx18/cx18-io.h [new file with mode: 0644]
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-irq.c
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-queue.c
drivers/media/video/cx18/cx18-scb.c
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx18/cx23418.h
drivers/media/video/cx2341x.c
drivers/media/video/cx23885/Kconfig
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-vbi.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/dabusb.c
drivers/media/video/dpc7146.c [deleted file]
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
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 [new file with mode: 0644]
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/m5602/Kconfig [new file with mode: 0644]
drivers/media/video/gspca/m5602/Makefile [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_bridge.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_core.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_mt9m111.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_mt9m111.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_ov9650.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_ov9650.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_po1030.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_po1030.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_s5k4aa.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_s5k4aa.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_s5k83a.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_s5k83a.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_sensor.h [new file with mode: 0644]
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/ov519.c
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/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.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-cards.h
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-fileops.h
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-ioctl.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/ivtv/ivtv-yuv.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/meye.c
drivers/media/video/meye.h
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c [new file with mode: 0644]
drivers/media/video/mt9v022.c
drivers/media/video/mxb.c
drivers/media/video/ov511.c
drivers/media/video/ov511.h
drivers/media/video/ovcamchip/ovcamchip_core.c
drivers/media/video/ovcamchip/ovcamchip_priv.h
drivers/media/video/pms.c
drivers/media/video/pvrusb2/pvrusb2-ctrl.c
drivers/media/video/pvrusb2/pvrusb2-ctrl.h
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-hdw.h
drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-main.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-ctrl.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pxa_camera.c
drivers/media/video/s2255drv.c
drivers/media/video/saa5246a.c
drivers/media/video/saa5246a.h [deleted file]
drivers/media/video/saa5249.c
drivers/media/video/saa7115.c
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-ts.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
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/sn9c102/sn9c102_hv7131d.c
drivers/media/video/sn9c102/sn9c102_hv7131r.c
drivers/media/video/sn9c102/sn9c102_mi0343.c
drivers/media/video/sn9c102/sn9c102_mi0360.c
drivers/media/video/sn9c102/sn9c102_mt9v111.c
drivers/media/video/sn9c102/sn9c102_ov7630.c
drivers/media/video/sn9c102/sn9c102_ov7660.c
drivers/media/video/sn9c102/sn9c102_pas106b.c
drivers/media/video/sn9c102/sn9c102_pas202bcb.c
drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
drivers/media/video/sn9c102/sn9c102_tas5110d.c
drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
drivers/media/video/stk-webcam.c
drivers/media/video/stk-webcam.h
drivers/media/video/stradis.c
drivers/media/video/stv680.c
drivers/media/video/tda9840.c
drivers/media/video/tda9840.h
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/tuner-3036.c [deleted file]
drivers/media/video/tuner-core.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-core.c
drivers/media/video/usbvision/usbvision-i2c.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_status.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/vino.c
drivers/media/video/vivi.c
drivers/media/video/vpx3220.c
drivers/media/video/w9966.c
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zoran/Kconfig [new file with mode: 0644]
drivers/media/video/zoran/Makefile [new file with mode: 0644]
drivers/media/video/zoran/videocodec.c [moved from drivers/media/video/videocodec.c with 100% similarity]
drivers/media/video/zoran/videocodec.h [moved from drivers/media/video/videocodec.h with 100% similarity]
drivers/media/video/zoran/zoran.h [moved from drivers/media/video/zoran.h with 100% similarity]
drivers/media/video/zoran/zoran_card.c [moved from drivers/media/video/zoran_card.c with 100% similarity]
drivers/media/video/zoran/zoran_card.h [moved from drivers/media/video/zoran_card.h with 100% similarity]
drivers/media/video/zoran/zoran_device.c [moved from drivers/media/video/zoran_device.c with 99% similarity]
drivers/media/video/zoran/zoran_device.h [moved from drivers/media/video/zoran_device.h with 94% similarity]
drivers/media/video/zoran/zoran_driver.c [moved from drivers/media/video/zoran_driver.c with 99% similarity]
drivers/media/video/zoran/zoran_procfs.c [moved from drivers/media/video/zoran_procfs.c with 100% similarity]
drivers/media/video/zoran/zoran_procfs.h [moved from drivers/media/video/zoran_procfs.h with 100% similarity]
drivers/media/video/zoran/zr36016.c [moved from drivers/media/video/zr36016.c with 100% similarity]
drivers/media/video/zoran/zr36016.h [moved from drivers/media/video/zr36016.h with 100% similarity]
drivers/media/video/zoran/zr36050.c [moved from drivers/media/video/zr36050.c with 100% similarity]
drivers/media/video/zoran/zr36050.h [moved from drivers/media/video/zr36050.h with 100% similarity]
drivers/media/video/zoran/zr36057.h [moved from drivers/media/video/zr36057.h with 100% similarity]
drivers/media/video/zoran/zr36060.c [moved from drivers/media/video/zr36060.c with 100% similarity]
drivers/media/video/zoran/zr36060.h [moved from drivers/media/video/zr36060.h with 100% similarity]
drivers/media/video/zr364xx.c
include/linux/dvb/frontend.h
include/linux/dvb/version.h
include/linux/i2c-id.h
include/linux/ivtv.h
include/linux/videodev2.h
include/media/ir-common.h
include/media/saa7115.h
include/media/saa7146.h
include/media/sh_mobile_ceu.h
include/media/soc_camera.h
include/media/tuner.h
include/media/v4l2-chip-ident.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-ioctl.h
include/sound/tea575x-tuner.h
sound/i2c/other/tea575x-tuner.c

index f32efb6..60ba668 100644 (file)
 149 -> Typhoon TV-Tuner PCI (50684)
 150 -> Geovision GV-600                                    [008a:763c]
 151 -> Kozumi KTV-01C
+152 -> Encore ENL TV-FM-2                                  [1000:1801]
index f0e613b..64823cc 100644 (file)
@@ -9,3 +9,5 @@
   8 -> Hauppauge WinTV-HVR1700                             [0070:8101]
   9 -> Hauppauge WinTV-HVR1400                             [0070:8010]
  10 -> DViCO FusionHDTV7 Dual Express                      [18ac:d618]
+ 11 -> DViCO FusionHDTV DVB-T Dual Express                 [18ac:db78]
+ 12 -> Leadtek Winfast PxDVR3200 H                         [107d:6681]
index 7cf5685..a5227e3 100644 (file)
  65 -> DViCO FusionHDTV 7 Gold                             [18ac:d610]
  66 -> Prolink Pixelview MPEG 8000GT                       [1554:4935]
  67 -> Kworld PlusTV HD PCI 120 (ATSC 120)                 [17de:08c1]
+ 68 -> Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid           [0070:6900,0070:6904,0070:6902]
+ 69 -> Hauppauge WinTV-HVR4000(Lite) DVB-S/S2              [0070:6905,0070:6906]
+ 70 -> TeVii S460 DVB-S/S2                                 [d460:9022]
+ 71 -> Omicom SS4 DVB-S/S2 PCI                             [A044:2011]
+ 72 -> TBS 8920 DVB-S/S2                                   [8920:8888]
+ 73 -> TeVii S420 DVB-S                                    [d420:9022]
+ 74 -> Prolink Pixelview Global Extreme                    [1554:4976]
+ 75 -> PROF 7300 DVB-S/S2                                  [B033:3033]
index 53449cb..187cc48 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:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
+  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2820,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,7 +12,7 @@
  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)
+ 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840) [eb1a:2821]
  15 -> V-Gear PocketTV                          (em2800)
  16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b,2040:651f]
  17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
index 39868af..dc67eef 100644 (file)
@@ -76,7 +76,7 @@
  75 -> AVerMedia AVerTVHD MCE A180              [1461:1044]
  76 -> SKNet MonsterTV Mobile                   [1131:4ee9]
  77 -> Pinnacle PCTV 40i/50i/110i (saa7133)     [11bd:002e]
- 78 -> ASUSTeK P7131 Dual                       [1043:4862,1043:4857]
+ 78 -> ASUSTeK P7131 Dual                       [1043:4862]
  79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
 144 -> Beholder BeholdTV M6 Extra               [5ace:6193]
 145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636]
 146 -> ASUSTeK P7131 Analog
+147 -> Asus Tiger 3in1                          [1043:4878]
+148 -> Encore ENLTV-FM v5.3                     [1a7f:2008]
+149 -> Avermedia PCI pure analog (M135A)        [1461:f11d]
+150 -> Zogis Real Angel 220
+151 -> ADS Tech Instant HDTV                    [1421:0380]
+152 -> Asus Tiger Rev:1.00                      [1043:4857]
index 0e23946..30bbdda 100644 (file)
@@ -74,3 +74,4 @@ tuner=72 - Thomson FE6600
 tuner=73 - Samsung TCPG 6121P30A
 tuner=75 - Philips TEA5761 FM Radio
 tuner=76 - Xceive 5000 tuner
+tuner=77 - TCL tuner MF02GIP-5N-E
index 9a3e4d7..004818f 100644 (file)
@@ -7,6 +7,7 @@ The modules are:
 xxxx           vend:prod
 ----
 spca501                0000:0000       MystFromOri Unknow Camera
+m5602          0402:5602       ALi Video Camera Controller
 spca501                040a:0002       Kodak DVC-325
 spca500                040a:0300       Kodak EZ200
 zc3xx          041e:041e       Creative WebCam Live!
@@ -42,6 +43,7 @@ zc3xx         0458:7007       Genius VideoCam V2
 zc3xx          0458:700c       Genius VideoCam V3
 zc3xx          0458:700f       Genius VideoCam Web V2
 sonixj         0458:7025       Genius Eye 311Q
+sonixj         0458:702e       Genius Slim 310 NB
 sonixj         045e:00f5       MicroSoft VX3000
 sonixj         045e:00f7       MicroSoft VX1000
 ov519          045e:028c       Micro$oft xbox cam
@@ -81,7 +83,7 @@ spca561               046d:092b       Labtec Webcam Plus
 spca561                046d:092c       Logitech QC chat Elch2
 spca561                046d:092d       Logitech QC Elch2
 spca561                046d:092e       Logitech QC Elch2
-spca561                046d:092f       Logitech QC Elch2
+spca561                046d:092f       Logitech  QuickCam Express Plus
 sunplus                046d:0960       Logitech ClickSmart 420
 sunplus                0471:0322       Philips DMVC1300K
 zc3xx          0471:0325       Philips SPC 200 NC
@@ -96,6 +98,29 @@ sunplus              04a5:3003       Benq DC 1300
 sunplus                04a5:3008       Benq DC 1500
 sunplus                04a5:300a       Benq DC 3410
 spca500                04a5:300c       Benq DC 1016
+finepix                04cb:0104       Fujifilm FinePix 4800
+finepix                04cb:0109       Fujifilm FinePix A202
+finepix                04cb:010b       Fujifilm FinePix A203
+finepix                04cb:010f       Fujifilm FinePix A204
+finepix                04cb:0111       Fujifilm FinePix A205
+finepix                04cb:0113       Fujifilm FinePix A210
+finepix                04cb:0115       Fujifilm FinePix A303
+finepix                04cb:0117       Fujifilm FinePix A310
+finepix                04cb:0119       Fujifilm FinePix F401
+finepix                04cb:011b       Fujifilm FinePix F402
+finepix                04cb:011d       Fujifilm FinePix F410
+finepix                04cb:0121       Fujifilm FinePix F601
+finepix                04cb:0123       Fujifilm FinePix F700
+finepix                04cb:0125       Fujifilm FinePix M603
+finepix                04cb:0127       Fujifilm FinePix S300
+finepix                04cb:0129       Fujifilm FinePix S304
+finepix                04cb:012b       Fujifilm FinePix S500
+finepix                04cb:012d       Fujifilm FinePix S602
+finepix                04cb:012f       Fujifilm FinePix S700
+finepix                04cb:0131       Fujifilm FinePix unknown model
+finepix                04cb:013b       Fujifilm FinePix unknown model
+finepix                04cb:013d       Fujifilm FinePix unknown model
+finepix                04cb:013f       Fujifilm FinePix F420
 sunplus                04f1:1001       JVC GC A50
 spca561                04fc:0561       Flexcam 100
 sunplus                04fc:500c       Sunplus CA500C
@@ -181,6 +206,7 @@ pac207              093a:2468       PAC207
 pac207         093a:2470       Genius GF112
 pac207         093a:2471       Genius VideoCam ge111
 pac207         093a:2472       Genius VideoCam ge110
+pac207         093a:2476       Genius e-Messenger 112
 pac7311                093a:2600       PAC7311 Typhoon
 pac7311                093a:2601       Philips SPC 610 NC
 pac7311                093a:2603       PAC7312
diff --git a/Documentation/video4linux/m5602.txt b/Documentation/video4linux/m5602.txt
new file mode 100644 (file)
index 0000000..4450ab1
--- /dev/null
@@ -0,0 +1,12 @@
+This document describes the ALi m5602 bridge connected
+to the following supported sensors:
+OmniVision OV9650,
+Samsung s5k83a,
+Samsung s5k4aa,
+Micron mt9m111,
+Pixel plus PO1030
+
+This driver mimics the windows drivers, which have a braindead implementation sending bayer-encoded frames at VGA resolution.
+In a perfect world we should be able to reprogram the m5602 and the connected sensor in hardware instead, supporting a range of resolutions and pixelformats
+
+Anyway, have fun and please report any bugs to m560x-driver-devel@lists.sourceforge.net
diff --git a/Documentation/video4linux/soc-camera.txt b/Documentation/video4linux/soc-camera.txt
new file mode 100644 (file)
index 0000000..178ef3c
--- /dev/null
@@ -0,0 +1,120 @@
+                       Soc-Camera Subsystem
+                       ====================
+
+Terminology
+-----------
+
+The following terms are used in this document:
+ - camera / camera device / camera sensor - a video-camera sensor chip, capable
+   of connecting to a variety of systems and interfaces, typically uses i2c for
+   control and configuration, and a parallel or a serial bus for data.
+ - camera host - an interface, to which a camera is connected. Typically a
+   specialised interface, present on many SoCs, e.g., PXA27x and PXA3xx, SuperH,
+   AVR32, i.MX27, i.MX31.
+ - camera host bus - a connection between a camera host and a camera. Can be
+   parallel or serial, consists of data and control lines, e.g., clock, vertical
+   and horizontal synchronization signals.
+
+Purpose of the soc-camera subsystem
+-----------------------------------
+
+The soc-camera subsystem provides a unified API between camera host drivers and
+camera sensor drivers. It implements a V4L2 interface to the user, currently
+only the mmap method is supported.
+
+This subsystem has been written to connect drivers for System-on-Chip (SoC)
+video capture interfaces with drivers for CMOS camera sensor chips to enable
+the reuse of sensor drivers with various hosts. The subsystem has been designed
+to support multiple camera host interfaces and multiple cameras per interface,
+although most applications have only one camera sensor.
+
+Existing drivers
+----------------
+
+As of 2.6.27-rc4 there are two host drivers in the mainline: pxa_camera.c for
+PXA27x SoCs and sh_mobile_ceu_camera.c for SuperH SoCs, and four sensor drivers:
+mt9m001.c, mt9m111.c, mt9v022.c and a generic soc_camera_platform.c driver. This
+list is not supposed to be updated, look for more examples in your tree.
+
+Camera host API
+---------------
+
+A host camera driver is registered using the
+
+soc_camera_host_register(struct soc_camera_host *);
+
+function. The host object can be initialized as follows:
+
+static struct soc_camera_host pxa_soc_camera_host = {
+       .drv_name       = PXA_CAM_DRV_NAME,
+       .ops            = &pxa_soc_camera_host_ops,
+};
+
+All camera host methods are passed in a struct soc_camera_host_ops:
+
+static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
+       .owner          = THIS_MODULE,
+       .add            = pxa_camera_add_device,
+       .remove         = pxa_camera_remove_device,
+       .suspend        = pxa_camera_suspend,
+       .resume         = pxa_camera_resume,
+       .set_fmt_cap    = pxa_camera_set_fmt_cap,
+       .try_fmt_cap    = pxa_camera_try_fmt_cap,
+       .init_videobuf  = pxa_camera_init_videobuf,
+       .reqbufs        = pxa_camera_reqbufs,
+       .poll           = pxa_camera_poll,
+       .querycap       = pxa_camera_querycap,
+       .try_bus_param  = pxa_camera_try_bus_param,
+       .set_bus_param  = pxa_camera_set_bus_param,
+};
+
+.add and .remove methods are called when a sensor is attached to or detached
+from the host, apart from performing host-internal tasks they shall also call
+sensor driver's .init and .release methods respectively. .suspend and .resume
+methods implement host's power-management functionality and its their
+responsibility to call respective sensor's methods. .try_bus_param and
+.set_bus_param are used to negotiate physical connection parameters between the
+host and the sensor. .init_videobuf is called by soc-camera core when a
+video-device is opened, further video-buffer management is implemented completely
+by the specific camera host driver. The rest of the methods are called from
+respective V4L2 operations.
+
+Camera API
+----------
+
+Sensor drivers can use struct soc_camera_link, typically provided by the
+platform, and used to specify to which camera host bus the sensor is connected,
+and arbitrarily provide platform .power and .reset methods for the camera.
+soc_camera_device_register() and soc_camera_device_unregister() functions are
+used to add a sensor driver to or remove one from the system. The registration
+function takes a pointer to struct soc_camera_device as the only parameter.
+This struct can be initialized as follows:
+
+       /* link to driver operations */
+       icd->ops        = &mt9m001_ops;
+       /* link to the underlying physical (e.g., i2c) device */
+       icd->control    = &client->dev;
+       /* window geometry */
+       icd->x_min      = 20;
+       icd->y_min      = 12;
+       icd->x_current  = 20;
+       icd->y_current  = 12;
+       icd->width_min  = 48;
+       icd->width_max  = 1280;
+       icd->height_min = 32;
+       icd->height_max = 1024;
+       icd->y_skip_top = 1;
+       /* camera bus ID, typically obtained from platform data */
+       icd->iface      = icl->bus_id;
+
+struct soc_camera_ops provides .probe and .remove methods, which are called by
+the soc-camera core, when a camera is matched against or removed from a camera
+host bus, .init, .release, .suspend, and .resume are called from the camera host
+driver as discussed above. Other members of this struct provide respective V4L2
+functionality.
+
+struct soc_camera_device also links to an array of struct soc_camera_data_format,
+listing pixel formats, supported by the camera.
+
+--
+Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
index 39516ce..31abe6d 100644 (file)
@@ -36,8 +36,6 @@
 
 struct pxacamera_platform_data {
        int (*init)(struct device *);
-       int (*power)(struct device *, int);
-       int (*reset)(struct device *, int);
 
        unsigned long flags;
        unsigned long mclk_10khz;
index 8fa91f8..4952aeb 100644 (file)
@@ -103,6 +103,56 @@ IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
 
 EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt);
 
+/* Mauro Carvalho Chehab <mchehab@infradead.org> */
+IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE] = {
+       [0x00] = KEY_POWER2,
+       [0x2e] = KEY_DOT,               /* '.' */
+       [0x01] = KEY_MODE,              /* TV/FM */
+
+       [0x05] = KEY_1,
+       [0x06] = KEY_2,
+       [0x07] = KEY_3,
+       [0x09] = KEY_4,
+       [0x0a] = KEY_5,
+       [0x0b] = KEY_6,
+       [0x0d] = KEY_7,
+       [0x0e] = KEY_8,
+       [0x0f] = KEY_9,
+       [0x11] = KEY_0,
+
+       [0x13] = KEY_RIGHT,             /* -> */
+       [0x12] = KEY_LEFT,              /* <- */
+
+       [0x17] = KEY_SLEEP,             /* Capturar Imagem */
+       [0x10] = KEY_SHUFFLE,           /* Amostra */
+
+       /* FIXME: The keys bellow aren't ok */
+
+       [0x43] = KEY_CHANNELUP,
+       [0x42] = KEY_CHANNELDOWN,
+       [0x1f] = KEY_VOLUMEUP,
+       [0x1e] = KEY_VOLUMEDOWN,
+       [0x0c] = KEY_ENTER,
+
+       [0x14] = KEY_MUTE,
+       [0x08] = KEY_AUDIO,
+
+       [0x03] = KEY_TEXT,
+       [0x04] = KEY_EPG,
+       [0x2b] = KEY_TV2,               /* TV2 */
+
+       [0x1d] = KEY_RED,
+       [0x1c] = KEY_YELLOW,
+       [0x41] = KEY_GREEN,
+       [0x40] = KEY_BLUE,
+
+       [0x1a] = KEY_PLAYPAUSE,
+       [0x19] = KEY_RECORD,
+       [0x18] = KEY_PLAY,
+       [0x1b] = KEY_STOP,
+};
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a);
+
 /* Attila Kondoros <attila.kondoros@chello.hu> */
 IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
 
@@ -467,7 +517,8 @@ EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci);
 
 /* ---------------------------------------------------------------------- */
 
-/* MSI TV@nywhere remote */
+/* MSI TV@nywhere MASTER remote */
+
 IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
        /* Keys 0 to 9 */
        [ 0x00 ] = KEY_0,
@@ -501,6 +552,95 @@ EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
 
 /* ---------------------------------------------------------------------- */
 
+/*
+  Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card
+  is marked "KS003". The controller is I2C at address 0x30, but does not seem
+  to respond to probes until a read is performed from a valid device.
+  I don't know why...
+
+  Note: This remote may be of similar or identical design to the
+  Pixelview remote (?).  The raw codes and duplicate button codes
+  appear to be the same.
+
+  Henry Wong <henry@stuffedcow.net>
+  Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com>
+
+*/
+
+IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE] = {
+
+/*  ---- Remote Button Layout ----
+
+    POWER   SOURCE  SCAN    MUTE
+    TV/FM   1       2       3
+    |>      4       5       6
+    <|      7       8       9
+    ^^UP    0       +       RECALL
+    vvDN    RECORD  STOP    PLAY
+
+       MINIMIZE          ZOOM
+
+                 CH+
+      VOL-                   VOL+
+                 CH-
+
+       SNAPSHOT           MTS
+
+     <<      FUNC    >>     RESET
+*/
+
+       [0x01] = KEY_KP1,             /* 1 */
+       [0x0b] = KEY_KP2,             /* 2 */
+       [0x1b] = KEY_KP3,             /* 3 */
+       [0x05] = KEY_KP4,             /* 4 */
+       [0x09] = KEY_KP5,             /* 5 */
+       [0x15] = KEY_KP6,             /* 6 */
+       [0x06] = KEY_KP7,             /* 7 */
+       [0x0a] = KEY_KP8,             /* 8 */
+       [0x12] = KEY_KP9,             /* 9 */
+       [0x02] = KEY_KP0,             /* 0 */
+       [0x10] = KEY_KPPLUS,          /* + */
+       [0x13] = KEY_AGAIN,           /* Recall */
+
+       [0x1e] = KEY_POWER,           /* Power */
+       [0x07] = KEY_TUNER,           /* Source */
+       [0x1c] = KEY_SEARCH,          /* Scan */
+       [0x18] = KEY_MUTE,            /* Mute */
+
+       [0x03] = KEY_RADIO,           /* TV/FM */
+       /* The next four keys are duplicates that appear to send the
+          same IR code as Ch+, Ch-, >>, and << .  The raw code assigned
+          to them is the actual code + 0x20 - they will never be
+          detected as such unless some way is discovered to distinguish
+          these buttons from those that have the same code. */
+       [0x3f] = KEY_RIGHT,           /* |> and Ch+ */
+       [0x37] = KEY_LEFT,            /* <| and Ch- */
+       [0x2c] = KEY_UP,              /* ^^Up and >> */
+       [0x24] = KEY_DOWN,            /* vvDn and << */
+
+       [0x00] = KEY_RECORD,          /* Record */
+       [0x08] = KEY_STOP,            /* Stop */
+       [0x11] = KEY_PLAY,            /* Play */
+
+       [0x0f] = KEY_CLOSE,           /* Minimize */
+       [0x19] = KEY_ZOOM,            /* Zoom */
+       [0x1a] = KEY_SHUFFLE,         /* Snapshot */
+       [0x0d] = KEY_LANGUAGE,        /* MTS */
+
+       [0x14] = KEY_VOLUMEDOWN,      /* Vol- */
+       [0x16] = KEY_VOLUMEUP,        /* Vol+ */
+       [0x17] = KEY_CHANNELDOWN,     /* Ch- */
+       [0x1f] = KEY_CHANNELUP,       /* Ch+ */
+
+       [0x04] = KEY_REWIND,          /* << */
+       [0x0e] = KEY_MENU,            /* Function */
+       [0x0c] = KEY_FASTFORWARD,     /* >> */
+       [0x1d] = KEY_RESTART,         /* Reset */
+};
+EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus);
+
+/* ---------------------------------------------------------------------- */
+
 /* Cinergy 1400 DVB-T */
 IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
        [ 0x01 ] = KEY_POWER,
@@ -1792,12 +1932,61 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
        [ 0x41 ] = KEY_GREEN,           /* AP2 */
        [ 0x47 ] = KEY_YELLOW,          /* AP3 */
        [ 0x57 ] = KEY_BLUE,            /* AP4 */
-
-
 };
-
 EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
 
+/* Encore ENLTV2-FM  - silver plastic - "Wand Media" written at the botton
+    Mauro Carvalho Chehab <mchehab@infradead.org> */
+IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE] = {
+       [0x4c] = KEY_POWER2,
+       [0x4a] = KEY_TUNER,
+       [0x40] = KEY_1,
+       [0x60] = KEY_2,
+       [0x50] = KEY_3,
+       [0x70] = KEY_4,
+       [0x48] = KEY_5,
+       [0x68] = KEY_6,
+       [0x58] = KEY_7,
+       [0x78] = KEY_8,
+       [0x44] = KEY_9,
+       [0x54] = KEY_0,
+
+       [0x64] = KEY_LAST,              /* +100 */
+       [0x4e] = KEY_AGAIN,             /* Recall */
+
+       [0x6c] = KEY_SWITCHVIDEOMODE,   /* Video Source */
+       [0x5e] = KEY_MENU,
+       [0x56] = KEY_SCREEN,
+       [0x7a] = KEY_SETUP,
+
+       [0x46] = KEY_MUTE,
+       [0x5c] = KEY_MODE,              /* Stereo */
+       [0x74] = KEY_INFO,
+       [0x7c] = KEY_CLEAR,
+
+       [0x55] = KEY_UP,
+       [0x49] = KEY_DOWN,
+       [0x7e] = KEY_LEFT,
+       [0x59] = KEY_RIGHT,
+       [0x6a] = KEY_ENTER,
+
+       [0x42] = KEY_VOLUMEUP,
+       [0x62] = KEY_VOLUMEDOWN,
+       [0x52] = KEY_CHANNELUP,
+       [0x72] = KEY_CHANNELDOWN,
+
+       [0x41] = KEY_RECORD,
+       [0x51] = KEY_SHUFFLE,   /* Snapshot */
+       [0x75] = KEY_TIME,      /* Timeshift */
+       [0x71] = KEY_TV2,       /* PIP */
+
+       [0x45] = KEY_REWIND,
+       [0x6f] = KEY_PAUSE,
+       [0x7d] = KEY_FORWARD,
+       [0x79] = KEY_STOP,
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2);
+
 /* for the Technotrend 1500 bundled remotes (grey and black): */
 IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
        [ 0x01 ] = KEY_POWER,
@@ -2239,3 +2428,86 @@ IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
        [0x2a] = KEY_MENU,
 };
 EXPORT_SYMBOL_GPL(ir_codes_avermedia_a16d);
+
+/* Encore ENLTV-FM v5.3
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE] = {
+       [0x10] = KEY_POWER2,
+       [0x06] = KEY_MUTE,
+
+       [0x09] = KEY_1,
+       [0x1d] = KEY_2,
+       [0x1f] = KEY_3,
+       [0x19] = KEY_4,
+       [0x1b] = KEY_5,
+       [0x11] = KEY_6,
+       [0x17] = KEY_7,
+       [0x12] = KEY_8,
+       [0x16] = KEY_9,
+       [0x48] = KEY_0,
+
+       [0x04] = KEY_LIST,              /* -/-- */
+       [0x40] = KEY_LAST,              /* recall */
+
+       [0x02] = KEY_MODE,              /* TV/AV */
+       [0x05] = KEY_SHUFFLE,           /* SNAPSHOT */
+
+       [0x4c] = KEY_CHANNELUP,         /* UP */
+       [0x00] = KEY_CHANNELDOWN,       /* DOWN */
+       [0x0d] = KEY_VOLUMEUP,          /* RIGHT */
+       [0x15] = KEY_VOLUMEDOWN,        /* LEFT */
+       [0x49] = KEY_ENTER,             /* OK */
+
+       [0x54] = KEY_RECORD,
+       [0x4d] = KEY_PLAY,              /* pause */
+
+       [0x1e] = KEY_UP,                /* video setting */
+       [0x0e] = KEY_RIGHT,             /* <- */
+       [0x1a] = KEY_LEFT,              /* -> */
+
+       [0x0a] = KEY_DOWN,              /* video default */
+       [0x0c] = KEY_ZOOM,              /* hide pannel */
+       [0x47] = KEY_SLEEP,             /* shutdown */
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv_fm53);
+
+/* Zogis Real Audio 220 - 32 keys IR */
+IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = {
+       [0x1c] = KEY_RADIO,
+       [0x12] = KEY_POWER2,
+
+       [0x01] = KEY_1,
+       [0x02] = KEY_2,
+       [0x03] = KEY_3,
+       [0x04] = KEY_4,
+       [0x05] = KEY_5,
+       [0x06] = KEY_6,
+       [0x07] = KEY_7,
+       [0x08] = KEY_8,
+       [0x09] = KEY_9,
+       [0x00] = KEY_0,
+
+       [0x0c] = KEY_VOLUMEUP,
+       [0x18] = KEY_VOLUMEDOWN,
+       [0x0b] = KEY_CHANNELUP,
+       [0x15] = KEY_CHANNELDOWN,
+       [0x16] = KEY_ENTER,
+
+       [0x11] = KEY_LIST,              /* Source */
+       [0x0d] = KEY_AUDIO,             /* stereo */
+
+       [0x0f] = KEY_PREVIOUS,          /* Prev */
+       [0x1b] = KEY_PAUSE,             /* Timeshift */
+       [0x1a] = KEY_NEXT,              /* Next */
+
+       [0x0e] = KEY_STOP,
+       [0x1f] = KEY_PLAY,
+       [0x1e] = KEY_PLAYPAUSE,         /* Pause */
+
+       [0x1d] = KEY_RECORD,
+       [0x13] = KEY_MUTE,
+       [0x19] = KEY_SHUFFLE,           /* Snapshot */
+
+};
+EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys);
index d01965e..d599d36 100644 (file)
@@ -234,7 +234,7 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
 int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
 {
        __le32       *cpu;
-       dma_addr_t   dma_addr;
+       dma_addr_t   dma_addr = 0;
 
        cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
        if (NULL == cpu) {
index cf6a817..5b34c13 100644 (file)
@@ -533,7 +533,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
        memcpy(vfd, &device_template, sizeof(struct video_device));
        strlcpy(vfd->name, name, sizeof(vfd->name));
        vfd->release = video_device_release;
-       vfd->priv = dev;
+       video_set_drvdata(vfd, dev);
 
        // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
        if (video_register_device(vfd, type, -1) < 0) {
index 1305b0e..12206d7 100644 (file)
@@ -170,6 +170,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
        b[0] = REG_LO1B1;
        b[1] = 0xFF;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
        mt2060_writeregs(priv,b,2);
 
        freq = params->frequency / 1000; // Hz -> kHz
@@ -233,6 +236,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
                i++;
        } while (i<10);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
        return ret;
 }
 
@@ -296,13 +302,35 @@ static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 static int mt2060_init(struct dvb_frontend *fe)
 {
        struct mt2060_priv *priv = fe->tuner_priv;
-       return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x33);
+       int ret;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       ret = mt2060_writereg(priv, REG_VGAG,
+                             (priv->cfg->clock_out << 6) | 0x33);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       return ret;
 }
 
 static int mt2060_sleep(struct dvb_frontend *fe)
 {
        struct mt2060_priv *priv = fe->tuner_priv;
-       return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
+       int ret;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+       ret = mt2060_writereg(priv, REG_VGAG,
+                             (priv->cfg->clock_out << 6) | 0x30);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+       return ret;
 }
 
 static int mt2060_release(struct dvb_frontend *fe)
@@ -344,6 +372,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
        priv->i2c      = i2c;
        priv->if1_freq = if1;
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
        if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
                kfree(priv);
                return NULL;
@@ -360,6 +391,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
 
        mt2060_calibrate(priv);
 
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
        return fe;
 }
 EXPORT_SYMBOL(mt2060_attach);
index cb25e43..64379f2 100644 (file)
@@ -979,7 +979,6 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
        switch (instance) {
        case 0:
                goto fail;
-               break;
        case 1:
                /* new tuner instance */
                state->config = cfg;
index 93063c6..1b48b5d 100644 (file)
@@ -1155,7 +1155,6 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
        switch (instance) {
        case 0:
                goto fail;
-               break;
        case 1:
                /* new tuner instance */
                priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
index 8555d9c..4a74f65 100644 (file)
@@ -447,17 +447,19 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
                        else
                                arg = 0;
                }
-               if (priv->cfg->tuner_callback)
-                       priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
-                                                               gp_func, arg);
+               if (fe->callback)
+                       fe->callback(priv->i2c_adap->algo_data,
+                                    DVB_FRONTEND_COMPONENT_TUNER,
+                                    gp_func, arg);
                buf[1] = high ? 0 : 1;
                if (priv->cfg->config == 2)
                        buf[1] = high ? 1 : 0;
                i2c_transfer(priv->i2c_adap, &msg, 1);
                break;
        case 3: /* switch with GPIO of saa713x */
-               if (priv->cfg->tuner_callback)
-                       priv->cfg->tuner_callback(priv->i2c_adap->algo_data, 0, high);
+               if (fe->callback)
+                       fe->callback(priv->i2c_adap->algo_data,
+                                    DVB_FRONTEND_COMPONENT_TUNER, 0, high);
                break;
        }
 }
index 7850a9a..7d72ce0 100644 (file)
@@ -36,7 +36,6 @@ struct tda827x_config
        /* interface to tda829x driver */
        unsigned int config;
        int          switch_addr;
-       int (*tuner_callback) (void *dev, int command, int arg);
 
        void (*agcf)(struct dvb_frontend *fe);
 };
index 91204d3..c112bdd 100644 (file)
@@ -672,10 +672,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
        priv->i2c_props.addr     = i2c_addr;
        priv->i2c_props.adap     = i2c_adap;
        priv->i2c_props.name     = "tda829x";
-       if (cfg) {
+       if (cfg)
                priv->cfg.config         = cfg->lna_cfg;
-               priv->cfg.tuner_callback = cfg->tuner_callback;
-       }
 
        if (tda8290_probe(&priv->i2c_props) == 0) {
                priv->ver = TDA8290;
index aa074f3..7e288b2 100644 (file)
@@ -22,7 +22,6 @@
 
 struct tda829x_config {
        unsigned int lna_cfg;
-       int (*tuner_callback) (void *dev, int command, int arg);
 
        unsigned int probe_tuner:1;
 #define TDA829X_PROBE_TUNER 0
index 72abf0b..ff1788c 100644 (file)
@@ -686,7 +686,6 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
        case 0:
                mutex_unlock(&tda9887_list_mutex);
                return NULL;
-               break;
        case 1:
                fe->analog_demod_priv = priv;
                priv->mode = T_STANDBY;
index aa773a6..2a1aac1 100644 (file)
@@ -142,6 +142,7 @@ static inline int tuner_stereo(const int type, const int status)
        case TUNER_PHILIPS_FM1236_MK3:
        case TUNER_PHILIPS_FM1256_IH3:
        case TUNER_LG_NTSC_TAPE:
+       case TUNER_TCL_MF02GIP_5N:
                return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
        default:
                return status & TUNER_STEREO;
@@ -494,6 +495,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
        case TUNER_PHILIPS_FMD1216ME_MK3:
        case TUNER_LG_NTSC_TAPE:
        case TUNER_PHILIPS_FM1256_IH3:
+       case TUNER_TCL_MF02GIP_5N:
                buffer[3] = 0x19;
                break;
        case TUNER_TNF_5335MF:
@@ -1038,7 +1040,6 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
        case 0:
                mutex_unlock(&tuner_simple_list_mutex);
                return NULL;
-               break;
        case 1:
                fe->tuner_priv = priv;
 
index 10dddca..04961a1 100644 (file)
@@ -1216,6 +1216,23 @@ static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
        },
 };
 
+/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */
+
+static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = {
+       { 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_NTSC,
+               .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges),
+               .cb_first_if_lower_freq = 1,
+       },
+};
+
 /* --------------------------------------------------------------------- */
 
 struct tunertype tuners[] = {
@@ -1641,6 +1658,11 @@ struct tunertype tuners[] = {
                .name   = "Xceive 5000 tuner",
                /* see xc5000.c for details */
        },
+       [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
+               .name   = "TCL tuner MF02GIP-5N-E",
+               .params = tuner_tcl_mf02gip_5n_params,
+               .count  = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
+       },
 };
 EXPORT_SYMBOL(tuners);
 
index 4dd1d24..b65e680 100644 (file)
@@ -71,9 +71,6 @@ struct firmware_properties {
 struct xc2028_data {
        struct list_head        hybrid_tuner_instance_list;
        struct tuner_i2c_props  i2c_props;
-       int                     (*tuner_callback) (void *dev,
-                                                  int command, int arg);
-       void                    *video_dev;
        __u32                   frequency;
 
        struct firmware_description *firm;
@@ -492,6 +489,23 @@ ret:
        return i;
 }
 
+static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+
+       /* analog side (tuner-core) uses i2c_adap->algo_data.
+        * digital side is not guaranteed to have algo_data defined.
+        *
+        * digital side will always have fe->dvb defined.
+        * analog side (tuner-core) doesn't (yet) define fe->dvb.
+        */
+
+       return (!fe->callback) ? -EINVAL :
+               fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+                               fe->dvb->priv : priv->i2c_props.adap->algo_data,
+                            DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
+}
+
 static int load_firmware(struct dvb_frontend *fe, unsigned int type,
                         v4l2_std_id *id)
 {
@@ -530,8 +544,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
 
                if (!size) {
                        /* Special callback command received */
-                       rc = priv->tuner_callback(priv->video_dev,
-                                                 XC2028_TUNER_RESET, 0);
+                       rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
                        if (rc < 0) {
                                tuner_err("Error at RESET code %d\n",
                                           (*p) & 0x7f);
@@ -542,8 +555,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
                if (size >= 0xff00) {
                        switch (size) {
                        case 0xff00:
-                               rc = priv->tuner_callback(priv->video_dev,
-                                                       XC2028_RESET_CLK, 0);
+                               rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
                                if (rc < 0) {
                                        tuner_err("Error at RESET code %d\n",
                                                  (*p) & 0x7f);
@@ -715,8 +727,7 @@ retry:
        memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
 
        /* Reset is needed before loading firmware */
-       rc = priv->tuner_callback(priv->video_dev,
-                                 XC2028_TUNER_RESET, 0);
+       rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
        if (rc < 0)
                goto fail;
 
@@ -933,7 +944,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
           The reset CLK is needed only with tm6000.
           Driver should work fine even if this fails.
         */
-       priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
+       do_tuner_callback(fe, XC2028_RESET_CLK, 1);
 
        msleep(10);
 
@@ -1002,11 +1013,6 @@ static int xc2028_set_params(struct dvb_frontend *fe,
 
        tuner_dbg("%s called\n", __func__);
 
-       if (priv->ctrl.d2633)
-               type |= D2633;
-       else
-               type |= D2620;
-
        switch(fe->ops.info.type) {
        case FE_OFDM:
                bw = p->u.ofdm.bandwidth;
@@ -1021,10 +1027,8 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                break;
        case FE_ATSC:
                bw = BANDWIDTH_6_MHZ;
-               /* The only ATSC firmware (at least on v2.7) is D2633,
-                  so overrides ctrl->d2633 */
-               type |= ATSC| D2633;
-               type &= ~D2620;
+               /* The only ATSC firmware (at least on v2.7) is D2633 */
+               type |= ATSC | D2633;
                break;
        /* DVB-S is not supported */
        default:
@@ -1057,6 +1061,28 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                tuner_err("error: bandwidth not supported.\n");
        };
 
+       /*
+         Selects between D2633 or D2620 firmware.
+         It doesn't make sense for ATSC, since it should be D2633 on all cases
+        */
+       if (fe->ops.info.type != FE_ATSC) {
+               switch (priv->ctrl.type) {
+               case XC2028_D2633:
+                       type |= D2633;
+                       break;
+               case XC2028_D2620:
+                       type |= D2620;
+                       break;
+               case XC2028_AUTO:
+               default:
+                       /* Zarlink seems to need D2633 */
+                       if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
+                               type |= D2633;
+                       else
+                               type |= D2620;
+               }
+       }
+
        /* All S-code tables need a 200kHz shift */
        if (priv->ctrl.demod)
                demod = priv->ctrl.demod + 200;
@@ -1177,20 +1203,10 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
                break;
        case 1:
                /* new tuner instance */
-               priv->tuner_callback = cfg->callback;
                priv->ctrl.max_len = 13;
 
                mutex_init(&priv->lock);
 
-               /* analog side (tuner-core) uses i2c_adap->algo_data.
-                * digital side is not guaranteed to have algo_data defined.
-                *
-                * digital side will always have fe->dvb defined.
-                * analog side (tuner-core) doesn't (yet) define fe->dvb.
-                */
-               priv->video_dev = ((fe->dvb) && (fe->dvb->priv)) ?
-                                  fe->dvb->priv : cfg->i2c_adap->algo_data;
-
                fe->tuner_priv = priv;
                break;
        case 2:
index 2c5b628..19de792 100644 (file)
 #define        XC3028_FE_ZARLINK456    4560
 #define        XC3028_FE_CHINA         5200
 
+enum firmware_type {
+       XC2028_AUTO = 0,        /* By default, auto-detects */
+       XC2028_D2633,
+       XC2028_D2620,
+};
+
 struct xc2028_ctrl {
        char                    *fname;
        int                     max_len;
        unsigned int            scode_table;
        unsigned int            mts   :1;
-       unsigned int            d2633 :1;
        unsigned int            input1:1;
        unsigned int            vhfbw7:1;
        unsigned int            uhfbw8:1;
        unsigned int            demod;
+       enum firmware_type      type:2;
 };
 
 struct xc2028_config {
        struct i2c_adapter *i2c_adap;
        u8                 i2c_addr;
-       void               *video_dev;
        struct xc2028_ctrl *ctrl;
-       int                (*callback) (void *dev, int command, int arg);
 };
 
 /* xc2028 commands for callback */
index dcddfa8..f9c2bb9 100644 (file)
@@ -30,7 +30,7 @@
 #include "dvb_frontend.h"
 
 #include "xc5000.h"
-#include "xc5000_priv.h"
+#include "tuner-i2c.h"
 
 static int debug;
 module_param(debug, int, 0644);
@@ -40,12 +40,26 @@ 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);
+
 #define dprintk(level,fmt, arg...) if (debug >= level) \
        printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
 #define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
 #define XC5000_DEFAULT_FIRMWARE_SIZE 12332
 
+struct xc5000_priv {
+       struct tuner_i2c_props i2c_props;
+       struct list_head hybrid_tuner_instance_list;
+
+       u32 if_khz;
+       u32 freq_hz;
+       u32 bandwidth;
+       u8  video_standard;
+       u8  rf_mode;
+};
+
 /* Misc Defines */
 #define MAX_TV_STANDARD                        23
 #define XC_MAX_I2C_WRITE_LENGTH                64
@@ -216,9 +230,12 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
 
        dprintk(1, "%s()\n", __func__);
 
-       if (priv->cfg->tuner_callback) {
-               ret = priv->cfg->tuner_callback(priv->devptr,
-                                               XC5000_TUNER_RESET, 0);
+       if (fe->callback) {
+               ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+                                          fe->dvb->priv :
+                                          priv->i2c_props.adap->algo_data,
+                                          DVB_FRONTEND_COMPONENT_TUNER,
+                                          XC5000_TUNER_RESET, 0);
                if (ret)
                        printk(KERN_ERR "xc5000: reset failed\n");
        } else
@@ -509,13 +526,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
        u8 buf[2] = { reg >> 8, reg & 0xff };
        u8 bval[2] = { 0, 0 };
        struct i2c_msg msg[2] = {
-               { .addr = priv->cfg->i2c_address,
+               { .addr = priv->i2c_props.addr,
                        .flags = 0, .buf = &buf[0], .len = 2 },
-               { .addr = priv->cfg->i2c_address,
+               { .addr = priv->i2c_props.addr,
                        .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
        };
 
-       if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+       if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
                printk(KERN_WARNING "xc5000: I2C read failed\n");
                return -EREMOTEIO;
        }
@@ -526,10 +543,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
 
 static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
 {
-       struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
                .flags = 0, .buf = buf, .len = len };
 
-       if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
                printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
                        (int)len);
                return -EREMOTEIO;
@@ -539,10 +556,10 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
 
 static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
 {
-       struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
                .flags = I2C_M_RD, .buf = buf, .len = len };
 
-       if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
                printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
                return -EREMOTEIO;
        }
@@ -559,7 +576,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
        printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
                XC5000_DEFAULT_FIRMWARE);
 
-       ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+       ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev);
        if (ret) {
                printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
                ret = XC_RESULT_RESET_FAILURE;
@@ -675,10 +692,10 @@ static int xc5000_set_params(struct dvb_frontend *fe,
                return -EREMOTEIO;
        }
 
-       ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+       ret = xc_set_IF_frequency(priv, priv->if_khz);
        if (ret != XC_RESULT_SUCCESS) {
                printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
-                       priv->cfg->if_khz);
+                      priv->if_khz);
                return -EIO;
        }
 
@@ -897,9 +914,19 @@ static int xc5000_init(struct dvb_frontend *fe)
 
 static int xc5000_release(struct dvb_frontend *fe)
 {
+       struct xc5000_priv *priv = fe->tuner_priv;
+
        dprintk(1, "%s()\n", __func__);
-       kfree(fe->tuner_priv);
+
+       mutex_lock(&xc5000_list_mutex);
+
+       if (priv)
+               hybrid_tuner_release_state(priv);
+
+       mutex_unlock(&xc5000_list_mutex);
+
        fe->tuner_priv = NULL;
+
        return 0;
 }
 
@@ -924,29 +951,43 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
 
 struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                                   struct i2c_adapter *i2c,
-                                  struct xc5000_config *cfg, void *devptr)
+                                  struct xc5000_config *cfg)
 {
        struct xc5000_priv *priv = NULL;
+       int instance;
        u16 id = 0;
 
-       dprintk(1, "%s()\n", __func__);
+       dprintk(1, "%s(%d-%04x)\n", __func__,
+               i2c ? i2c_adapter_id(i2c) : -1,
+               cfg ? cfg->i2c_address : -1);
 
-       priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
-       if (priv == NULL)
-               return NULL;
+       mutex_lock(&xc5000_list_mutex);
 
-       priv->cfg = cfg;
-       priv->bandwidth = BANDWIDTH_6_MHZ;
-       priv->i2c = i2c;
-       priv->devptr = devptr;
+       instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
+                                             hybrid_tuner_instance_list,
+                                             i2c, cfg->i2c_address, "xc5000");
+       switch (instance) {
+       case 0:
+               goto fail;
+               break;
+       case 1:
+               /* new tuner instance */
+               priv->bandwidth = BANDWIDTH_6_MHZ;
+               priv->if_khz = cfg->if_khz;
+
+               fe->tuner_priv = priv;
+               break;
+       default:
+               /* existing tuner instance */
+               fe->tuner_priv = priv;
+               break;
+       }
 
        /* Check if firmware has been loaded. It is possible that another
           instance of the driver has loaded the firmware.
         */
-       if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
-               kfree(priv);
-               return NULL;
-       }
+       if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+               goto fail;
 
        switch(id) {
        case XC_PRODUCT_ID_FW_LOADED:
@@ -967,19 +1008,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                printk(KERN_ERR
                        "xc5000: Device not found at addr 0x%02x (0x%x)\n",
                        cfg->i2c_address, id);
-               kfree(priv);
-               return NULL;
+               goto fail;
        }
 
+       mutex_unlock(&xc5000_list_mutex);
+
        memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
                sizeof(struct dvb_tuner_ops));
 
-       fe->tuner_priv = priv;
-
        if (xc5000_load_fw_on_attach)
                xc5000_init(fe);
 
        return fe;
+fail:
+       mutex_unlock(&xc5000_list_mutex);
+
+       xc5000_release(fe);
+       return NULL;
 }
 EXPORT_SYMBOL(xc5000_attach);
 
index 5389f74..cf1a558 100644 (file)
@@ -30,8 +30,6 @@ struct i2c_adapter;
 struct xc5000_config {
        u8   i2c_address;
        u32  if_khz;
-
-       int  (*tuner_callback) (void *priv, int command, int arg);
 };
 
 /* xc5000 callback command */
@@ -49,13 +47,11 @@ struct xc5000_config {
     (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
 extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
                                          struct i2c_adapter *i2c,
-                                         struct xc5000_config *cfg,
-                                         void *devptr);
+                                         struct xc5000_config *cfg);
 #else
 static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
                                                 struct i2c_adapter *i2c,
-                                                struct xc5000_config *cfg,
-                                                void *devptr)
+                                                struct xc5000_config *cfg)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
deleted file mode 100644 (file)
index b2a0074..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
- *
- *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
- *
- *  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 XC5000_PRIV_H
-#define XC5000_PRIV_H
-
-struct xc5000_priv {
-       struct xc5000_config *cfg;
-       struct i2c_adapter   *i2c;
-
-       u32 freq_hz;
-       u32 bandwidth;
-       u8  video_standard;
-       u8  rf_mode;
-
-       void *devptr;
-};
-
-#endif
index 8bc1445..0bcd852 100644 (file)
@@ -20,7 +20,6 @@ comment "Supported USB Adapters"
 source "drivers/media/dvb/dvb-usb/Kconfig"
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
-source "drivers/media/dvb/cinergyT2/Kconfig"
 source "drivers/media/dvb/siano/Kconfig"
 
 comment "Supported FlexCopII (B2C2) Adapters"
@@ -35,6 +34,10 @@ comment "Supported Pluto2 Adapters"
        depends on DVB_CORE && PCI && I2C
 source "drivers/media/dvb/pluto2/Kconfig"
 
+comment "Supported SDMC DM1105 Adapters"
+       depends on DVB_CORE && PCI && I2C
+source "drivers/media/dvb/dm1105/Kconfig"
+
 comment "Supported DVB Frontends"
        depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
index d6ba4d1..f91e9eb 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/
+obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
index a91ed28..26f0011 100644 (file)
@@ -10,7 +10,7 @@
 int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
 {
        u8 *tcpu;
-       dma_addr_t tdma;
+       dma_addr_t tdma = 0;
 
        if (size % 2) {
                err("dma buffersize has to be even.");
index 6afbfbb..48762a2 100644 (file)
@@ -702,7 +702,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
        }
 
        if (card->fe == NULL)
-               printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+               printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
                       card->bt->dev->vendor,
                       card->bt->dev->device,
                       card->bt->dev->subsystem_vendor,
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
deleted file mode 100644 (file)
index c03513b..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-config DVB_CINERGYT2
-       tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver"
-       depends on DVB_CORE && USB && INPUT
-       help
-         Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
-
-         Say Y if you own such a device and want to use it.
-
-
-config DVB_CINERGYT2_TUNING
-       bool "sophisticated fine-tuning for CinergyT2 cards"
-       depends on DVB_CINERGYT2
-       help
-         Here you can fine-tune some parameters of the CinergyT2 driver.
-
-         Normally you don't need to touch this, but in exotic setups you
-         may fine-tune your setup and adjust e.g. DMA buffer sizes for
-         a particular application.
-
-
-config DVB_CINERGYT2_STREAM_URB_COUNT
-       int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
-       depends on DVB_CINERGYT2_TUNING
-       default "32"
-       help
-         USB Request Blocks for Highspeed Stream transfers are scheduled in
-         a queue for the Host Controller.
-
-         Usually the default value is a safe choice.
-
-         You may increase this number if you are using this device in a
-         Server Environment with many high-traffic USB Highspeed devices
-         sharing the same USB bus.
-
-
-config DVB_CINERGYT2_STREAM_BUF_SIZE
-       int "Size of URB Stream Buffers for Highspeed Transfers"
-       depends on DVB_CINERGYT2_TUNING
-       default "512"
-       help
-         Should be a multiple of native buffer size of 512 bytes.
-         Default value is a safe choice.
-
-         You may increase this number if you are using this device in a
-         Server Environment with many high-traffic USB Highspeed devices
-         sharing the same USB bus.
-
-
-config DVB_CINERGYT2_QUERY_INTERVAL
-       int "Status update interval [milliseconds]"
-       depends on DVB_CINERGYT2_TUNING
-       default "250"
-       help
-         This is the interval for status readouts from the demodulator.
-         You may try lower values if you need more responsive signal quality
-         measurements.
-
-         Please keep in mind that these updates cause traffic on the tuner
-         control bus and thus may or may not affect reception sensitivity.
-
-         The default value should be a safe choice for common applications.
-
-
-config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-       bool "Register the onboard IR Remote Control Receiver as Input Device"
-       depends on DVB_CINERGYT2_TUNING
-       default y
-       help
-         Enable this option if you want to use the onboard Infrared Remote
-         Control Receiver as Linux-Input device.
-
-         Right now only the keycode table for the default Remote Control
-         delivered with the device is supported, please see the driver
-         source code to find out how to add support for other controls.
-
-
-config DVB_CINERGYT2_RC_QUERY_INTERVAL
-       int "Infrared Remote Controller update interval [milliseconds]"
-       depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-       default "50"
-       help
-         If you have a very fast-repeating remote control you can try lower
-         values, for normal consumer receivers the default value should be
-         a safe choice.
-
diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile
deleted file mode 100644 (file)
index d762d8c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
-
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
deleted file mode 100644 (file)
index a824f37..0000000
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*
- * TerraTec Cinergy T²/qanu USB2 DVB-T adapter.
- *
- * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
- *                 Holger Waechtler <holger@qanu.de>
- *
- *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/input.h>
-#include <linux/dvb/frontend.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-
-#include "dmxdev.h"
-#include "dvb_demux.h"
-#include "dvb_net.h"
-
-#ifdef CONFIG_DVB_CINERGYT2_TUNING
-       #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT)
-       #define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE)
-       #define QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_QUERY_INTERVAL)
-       #ifdef CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
-               #define RC_QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL)
-               #define ENABLE_RC (1)
-       #endif
-#else
-       #define STREAM_URB_COUNT (32)
-       #define STREAM_BUF_SIZE (512)   /* bytes */
-       #define ENABLE_RC (1)
-       #define RC_QUERY_INTERVAL (50)  /* milliseconds */
-       #define QUERY_INTERVAL (333)    /* milliseconds */
-#endif
-
-#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
-
-static int debug;
-module_param_named(debug, debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define dprintk(level, args...)                                                \
-do {                                                                   \
-       if ((debug & level)) {                                          \
-               printk("%s: %s(): ", KBUILD_MODNAME,                    \
-                      __func__);                                       \
-               printk(args); }                                         \
-} while (0)
-
-enum cinergyt2_ep1_cmd {
-       CINERGYT2_EP1_PID_TABLE_RESET           = 0x01,
-       CINERGYT2_EP1_PID_SETUP                 = 0x02,
-       CINERGYT2_EP1_CONTROL_STREAM_TRANSFER   = 0x03,
-       CINERGYT2_EP1_SET_TUNER_PARAMETERS      = 0x04,
-       CINERGYT2_EP1_GET_TUNER_STATUS          = 0x05,
-       CINERGYT2_EP1_START_SCAN                = 0x06,
-       CINERGYT2_EP1_CONTINUE_SCAN             = 0x07,
-       CINERGYT2_EP1_GET_RC_EVENTS             = 0x08,
-       CINERGYT2_EP1_SLEEP_MODE                = 0x09
-};
-
-struct dvbt_set_parameters_msg {
-       uint8_t cmd;
-       __le32 freq;
-       uint8_t bandwidth;
-       __le16 tps;
-       uint8_t flags;
-} __attribute__((packed));
-
-struct dvbt_get_status_msg {
-       __le32 freq;
-       uint8_t bandwidth;
-       __le16 tps;
-       uint8_t flags;
-       __le16 gain;
-       uint8_t snr;
-       __le32 viterbi_error_rate;
-       __le32 rs_error_rate;
-       __le32 uncorrected_block_count;
-       uint8_t lock_bits;
-       uint8_t prev_lock_bits;
-} __attribute__((packed));
-
-static struct dvb_frontend_info cinergyt2_fe_info = {
-       .name = DRIVER_NAME,
-       .type = FE_OFDM,
-       .frequency_min = 174000000,
-       .frequency_max = 862000000,
-       .frequency_stepsize = 166667,
-       .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_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
-};
-
-struct cinergyt2 {
-       struct dvb_demux demux;
-       struct usb_device *udev;
-       struct mutex sem;
-       struct mutex wq_sem;
-       struct dvb_adapter adapter;
-       struct dvb_device *fedev;
-       struct dmxdev dmxdev;
-       struct dvb_net dvbnet;
-
-       int streaming;
-       int sleeping;
-
-       struct dvbt_set_parameters_msg param;
-       struct dvbt_get_status_msg status;
-       struct delayed_work query_work;
-
-       wait_queue_head_t poll_wq;
-       int pending_fe_events;
-       int disconnect_pending;
-       unsigned int uncorrected_block_count;
-       atomic_t inuse;
-
-       void *streambuf;
-       dma_addr_t streambuf_dmahandle;
-       struct urb *stream_urb [STREAM_URB_COUNT];
-
-#ifdef ENABLE_RC
-       struct input_dev *rc_input_dev;
-       char phys[64];
-       struct delayed_work rc_query_work;
-       int rc_input_event;
-       __le32 rc_last_code;
-       unsigned long last_event_jiffies;
-#endif
-};
-
-enum {
-       CINERGYT2_RC_EVENT_TYPE_NONE = 0x00,
-       CINERGYT2_RC_EVENT_TYPE_NEC  = 0x01,
-       CINERGYT2_RC_EVENT_TYPE_RC5  = 0x02
-};
-
-struct cinergyt2_rc_event {
-       char type;
-       __le32 value;
-} __attribute__((packed));
-
-static const uint32_t rc_keys[] = {
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfe01eb04,     KEY_POWER,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfd02eb04,     KEY_1,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfc03eb04,     KEY_2,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfb04eb04,     KEY_3,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfa05eb04,     KEY_4,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf906eb04,     KEY_5,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf807eb04,     KEY_6,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf708eb04,     KEY_7,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf609eb04,     KEY_8,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf50aeb04,     KEY_9,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf30ceb04,     KEY_0,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf40beb04,     KEY_VIDEO,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf20deb04,     KEY_REFRESH,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf10eeb04,     KEY_SELECT,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf00feb04,     KEY_EPG,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xef10eb04,     KEY_UP,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xeb14eb04,     KEY_DOWN,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xee11eb04,     KEY_LEFT,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xec13eb04,     KEY_RIGHT,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xed12eb04,     KEY_OK,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xea15eb04,     KEY_TEXT,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe916eb04,     KEY_INFO,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe817eb04,     KEY_RED,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe718eb04,     KEY_GREEN,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe619eb04,     KEY_YELLOW,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe51aeb04,     KEY_BLUE,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe31ceb04,     KEY_VOLUMEUP,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe11eeb04,     KEY_VOLUMEDOWN,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe21deb04,     KEY_MUTE,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe41beb04,     KEY_CHANNELUP,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe01feb04,     KEY_CHANNELDOWN,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xbf40eb04,     KEY_PAUSE,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xb34ceb04,     KEY_PLAY,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xa758eb04,     KEY_RECORD,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xab54eb04,     KEY_PREVIOUS,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xb748eb04,     KEY_STOP,
-       CINERGYT2_RC_EVENT_TYPE_NEC,    0xa35ceb04,     KEY_NEXT
-};
-
-static int cinergyt2_command (struct cinergyt2 *cinergyt2,
-                             char *send_buf, int send_buf_len,
-                             char *recv_buf, int recv_buf_len)
-{
-       int actual_len;
-       char dummy;
-       int ret;
-
-       ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1),
-                          send_buf, send_buf_len, &actual_len, 1000);
-
-       if (ret)
-               dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret);
-
-       if (!recv_buf)
-               recv_buf = &dummy;
-
-       ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1),
-                          recv_buf, recv_buf_len, &actual_len, 1000);
-
-       if (ret)
-               dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret);
-
-       return ret ? ret : actual_len;
-}
-
-static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable)
-{
-       char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
-       cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
-}
-
-static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep)
-{
-       char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 };
-       cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
-       cinergyt2->sleeping = sleep;
-}
-
-static void cinergyt2_stream_irq (struct urb *urb);
-
-static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb)
-{
-       int err;
-
-       usb_fill_bulk_urb(urb,
-                         cinergyt2->udev,
-                         usb_rcvbulkpipe(cinergyt2->udev, 0x2),
-                         urb->transfer_buffer,
-                         STREAM_BUF_SIZE,
-                         cinergyt2_stream_irq,
-                         cinergyt2);
-
-       if ((err = usb_submit_urb(urb, GFP_ATOMIC)))
-               dprintk(1, "urb submission failed (err = %i)!\n", err);
-
-       return err;
-}
-
-static void cinergyt2_stream_irq (struct urb *urb)
-{
-       struct cinergyt2 *cinergyt2 = urb->context;
-
-       if (urb->actual_length > 0)
-               dvb_dmx_swfilter(&cinergyt2->demux,
-                                urb->transfer_buffer, urb->actual_length);
-
-       if (cinergyt2->streaming)
-               cinergyt2_submit_stream_urb(cinergyt2, urb);
-}
-
-static void cinergyt2_free_stream_urbs (struct cinergyt2 *cinergyt2)
-{
-       int i;
-
-       for (i=0; i<STREAM_URB_COUNT; i++)
-               usb_free_urb(cinergyt2->stream_urb[i]);
-
-       usb_buffer_free(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE,
-                           cinergyt2->streambuf, cinergyt2->streambuf_dmahandle);
-}
-
-static int cinergyt2_alloc_stream_urbs (struct cinergyt2 *cinergyt2)
-{
-       int i;
-
-       cinergyt2->streambuf = usb_buffer_alloc(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE,
-                                             GFP_KERNEL, &cinergyt2->streambuf_dmahandle);
-       if (!cinergyt2->streambuf) {
-               dprintk(1, "failed to alloc consistent stream memory area, bailing out!\n");
-               return -ENOMEM;
-       }
-
-       memset(cinergyt2->streambuf, 0, STREAM_URB_COUNT*STREAM_BUF_SIZE);
-
-       for (i=0; i<STREAM_URB_COUNT; i++) {
-               struct urb *urb;
-
-               if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) {
-                       dprintk(1, "failed to alloc consistent stream urbs, bailing out!\n");
-                       cinergyt2_free_stream_urbs(cinergyt2);
-                       return -ENOMEM;
-               }
-
-               urb->transfer_buffer = cinergyt2->streambuf + i * STREAM_BUF_SIZE;
-               urb->transfer_buffer_length = STREAM_BUF_SIZE;
-
-               cinergyt2->stream_urb[i] = urb;
-       }
-
-       return 0;
-}
-
-static void cinergyt2_stop_stream_xfer (struct cinergyt2 *cinergyt2)
-{
-       int i;
-
-       cinergyt2_control_stream_transfer(cinergyt2, 0);
-
-       for (i=0; i<STREAM_URB_COUNT; i++)
-               usb_kill_urb(cinergyt2->stream_urb[i]);
-}
-
-static int cinergyt2_start_stream_xfer (struct cinergyt2 *cinergyt2)
-{
-       int i, err;
-
-       for (i=0; i<STREAM_URB_COUNT; i++) {
-               if ((err = cinergyt2_submit_stream_urb(cinergyt2, cinergyt2->stream_urb[i]))) {
-                       cinergyt2_stop_stream_xfer(cinergyt2);
-                       dprintk(1, "failed urb submission (%i: err = %i)!\n", i, err);
-                       return err;
-               }
-       }
-
-       cinergyt2_control_stream_transfer(cinergyt2, 1);
-       return 0;
-}
-
-static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       struct dvb_demux *demux = dvbdmxfeed->demux;
-       struct cinergyt2 *cinergyt2 = demux->priv;
-
-       if (cinergyt2->disconnect_pending)
-               return -EAGAIN;
-       if (mutex_lock_interruptible(&cinergyt2->sem))
-               return -ERESTARTSYS;
-
-       if (cinergyt2->streaming == 0)
-               cinergyt2_start_stream_xfer(cinergyt2);
-
-       cinergyt2->streaming++;
-       mutex_unlock(&cinergyt2->sem);
-       return 0;
-}
-
-static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
-       struct dvb_demux *demux = dvbdmxfeed->demux;
-       struct cinergyt2 *cinergyt2 = demux->priv;
-
-       if (cinergyt2->disconnect_pending)
-               return -EAGAIN;
-       if (mutex_lock_interruptible(&cinergyt2->sem))
-               return -ERESTARTSYS;
-
-       if (--cinergyt2->streaming == 0)
-               cinergyt2_stop_stream_xfer(cinergyt2);
-
-       mutex_unlock(&cinergyt2->sem);
-       return 0;
-}
-
-/**
- *  convert linux-dvb frontend parameter set into TPS.
- *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
- *
- *  This function is probably reusable and may better get placed in a support
- *  library.
- *
- *  We replace errornous fields by default TPS fields (the ones with value 0).
- */
-static uint16_t compute_tps (struct dvb_frontend_parameters *p)
-{
-       struct dvb_ofdm_parameters *op = &p->u.ofdm;
-       uint16_t tps = 0;
-
-       switch (op->code_rate_HP) {
-               case FEC_2_3:
-                       tps |= (1 << 7);
-                       break;
-               case FEC_3_4:
-                       tps |= (2 << 7);
-                       break;
-               case FEC_5_6:
-                       tps |= (3 << 7);
-                       break;
-               case FEC_7_8:
-                       tps |= (4 << 7);
-                       break;
-               case FEC_1_2:
-               case FEC_AUTO:
-               default:
-                       /* tps |= (0 << 7) */;
-       }
-
-       switch (op->code_rate_LP) {
-               case FEC_2_3:
-                       tps |= (1 << 4);
-                       break;
-               case FEC_3_4:
-                       tps |= (2 << 4);
-                       break;
-               case FEC_5_6:
-                       tps |= (3 << 4);
-                       break;
-               case FEC_7_8:
-                       tps |= (4 << 4);
-                       break;
-               case FEC_1_2:
-               case FEC_AUTO:
-               default:
-                       /* tps |= (0 << 4) */;
-       }
-
-       switch (op->constellation) {
-               case QAM_16:
-                       tps |= (1 << 13);
-                       break;
-               case QAM_64:
-                       tps |= (2 << 13);
-                       break;
-               case QPSK:
-               default:
-                       /* tps |= (0 << 13) */;
-       }
-
-       switch (op->transmission_mode) {
-               case TRANSMISSION_MODE_8K:
-                       tps |= (1 << 0);
-                       break;
-               case TRANSMISSION_MODE_2K:
-               default:
-                       /* tps |= (0 << 0) */;
-       }
-
-       switch (op->guard_interval) {
-               case GUARD_INTERVAL_1_16:
-                       tps |= (1 << 2);
-                       break;
-               case GUARD_INTERVAL_1_8:
-                       tps |= (2 << 2);
-                       break;
-               case GUARD_INTERVAL_1_4:
-                       tps |= (3 << 2);
-                       break;
-               case GUARD_INTERVAL_1_32:
-               default:
-                       /* tps |= (0 << 2) */;
-       }
-
-       switch (op->hierarchy_information) {
-               case HIERARCHY_1:
-                       tps |= (1 << 10);
-                       break;
-               case HIERARCHY_2:
-                       tps |= (2 << 10);
-                       break;
-               case HIERARCHY_4:
-                       tps |= (3 << 10);
-                       break;
-               case HIERARCHY_NONE:
-               default:
-                       /* tps |= (0 << 10) */;
-       }
-
-       return tps;
-}
-
-static int cinergyt2_open (struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       int err = -EAGAIN;
-
-       if (cinergyt2->disconnect_pending)
-               goto out;
-       err = mutex_lock_interruptible(&cinergyt2->wq_sem);
-       if (err)
-               goto out;
-
-       err = mutex_lock_interruptible(&cinergyt2->sem);
-       if (err)
-               goto out_unlock1;
-
-       if ((err = dvb_generic_open(inode, file)))
-               goto out_unlock2;
-
-       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-               cinergyt2_sleep(cinergyt2, 0);
-               schedule_delayed_work(&cinergyt2->query_work, HZ/2);
-       }
-
-       atomic_inc(&cinergyt2->inuse);
-
-out_unlock2:
-       mutex_unlock(&cinergyt2->sem);
-out_unlock1:
-       mutex_unlock(&cinergyt2->wq_sem);
-out:
-       return err;
-}
-
-static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
-{
-       dvb_net_release(&cinergyt2->dvbnet);
-       dvb_dmxdev_release(&cinergyt2->dmxdev);
-       dvb_dmx_release(&cinergyt2->demux);
-       dvb_unregister_device(cinergyt2->fedev);
-       dvb_unregister_adapter(&cinergyt2->adapter);
-
-       cinergyt2_free_stream_urbs(cinergyt2);
-       kfree(cinergyt2);
-}
-
-static int cinergyt2_release (struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-
-       mutex_lock(&cinergyt2->wq_sem);
-
-       if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
-               cancel_rearming_delayed_work(&cinergyt2->query_work);
-
-               mutex_lock(&cinergyt2->sem);
-               cinergyt2_sleep(cinergyt2, 1);
-               mutex_unlock(&cinergyt2->sem);
-       }
-
-       mutex_unlock(&cinergyt2->wq_sem);
-
-       if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
-               warn("delayed unregister in release");
-               cinergyt2_unregister(cinergyt2);
-       }
-
-       return dvb_generic_release(inode, file);
-}
-
-static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       unsigned int mask = 0;
-
-       if (cinergyt2->disconnect_pending)
-               return -EAGAIN;
-       if (mutex_lock_interruptible(&cinergyt2->sem))
-               return -ERESTARTSYS;
-
-       poll_wait(file, &cinergyt2->poll_wq, wait);
-
-       if (cinergyt2->pending_fe_events != 0)
-               mask |= (POLLIN | POLLRDNORM | POLLPRI);
-
-       mutex_unlock(&cinergyt2->sem);
-
-       return mask;
-}
-
-
-static int cinergyt2_ioctl (struct inode *inode, struct file *file,
-                    unsigned cmd, unsigned long arg)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       struct dvbt_get_status_msg *stat = &cinergyt2->status;
-       fe_status_t status = 0;
-
-       switch (cmd) {
-       case FE_GET_INFO:
-               return copy_to_user((void __user*) arg, &cinergyt2_fe_info,
-                                   sizeof(struct dvb_frontend_info));
-
-       case FE_READ_STATUS:
-               if (0xffff - le16_to_cpu(stat->gain) > 30)
-                       status |= FE_HAS_SIGNAL;
-               if (stat->lock_bits & (1 << 6))
-                       status |= FE_HAS_LOCK;
-               if (stat->lock_bits & (1 << 5))
-                       status |= FE_HAS_SYNC;
-               if (stat->lock_bits & (1 << 4))
-                       status |= FE_HAS_CARRIER;
-               if (stat->lock_bits & (1 << 1))
-                       status |= FE_HAS_VITERBI;
-
-               return copy_to_user((void  __user*) arg, &status, sizeof(status));
-
-       case FE_READ_BER:
-               return put_user(le32_to_cpu(stat->viterbi_error_rate),
-                               (__u32 __user *) arg);
-
-       case FE_READ_SIGNAL_STRENGTH:
-               return put_user(0xffff - le16_to_cpu(stat->gain),
-                               (__u16 __user *) arg);
-
-       case FE_READ_SNR:
-               return put_user((stat->snr << 8) | stat->snr,
-                               (__u16 __user *) arg);
-
-       case FE_READ_UNCORRECTED_BLOCKS:
-       {
-               uint32_t unc_count;
-
-               if (mutex_lock_interruptible(&cinergyt2->sem))
-                       return -ERESTARTSYS;
-               unc_count = cinergyt2->uncorrected_block_count;
-               cinergyt2->uncorrected_block_count = 0;
-               mutex_unlock(&cinergyt2->sem);
-
-               /* UNC are already converted to host byte order... */
-               return put_user(unc_count,(__u32 __user *) arg);
-       }
-       case FE_SET_FRONTEND:
-       {
-               struct dvbt_set_parameters_msg *param = &cinergyt2->param;
-               struct dvb_frontend_parameters p;
-               int err;
-
-               if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-                       return -EPERM;
-
-               if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
-                       return -EFAULT;
-
-               if (cinergyt2->disconnect_pending)
-                       return -EAGAIN;
-               if (mutex_lock_interruptible(&cinergyt2->sem))
-                       return -ERESTARTSYS;
-
-               param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
-               param->tps = cpu_to_le16(compute_tps(&p));
-               param->freq = cpu_to_le32(p.frequency / 1000);
-               param->bandwidth = 8 - p.u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
-
-               stat->lock_bits = 0;
-               cinergyt2->pending_fe_events++;
-               wake_up_interruptible(&cinergyt2->poll_wq);
-
-               err = cinergyt2_command(cinergyt2,
-                                       (char *) param, sizeof(*param),
-                                       NULL, 0);
-
-               mutex_unlock(&cinergyt2->sem);
-
-               return (err < 0) ? err : 0;
-       }
-
-       case FE_GET_FRONTEND:
-               /**
-                *  trivial to implement (see struct dvbt_get_status_msg).
-                *  equivalent to FE_READ ioctls, but needs
-                *  TPS -> linux-dvb parameter set conversion. Feel free
-                *  to implement this and send us a patch if you need this
-                *  functionality.
-                */
-               break;
-
-       case FE_GET_EVENT:
-       {
-               /**
-                *  for now we only fill the status field. the parameters
-                *  are trivial to fill as soon FE_GET_FRONTEND is done.
-                */
-               struct dvb_frontend_event __user *e = (void __user *) arg;
-               if (cinergyt2->pending_fe_events == 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return -EWOULDBLOCK;
-                       wait_event_interruptible(cinergyt2->poll_wq,
-                                                cinergyt2->pending_fe_events > 0);
-               }
-               cinergyt2->pending_fe_events = 0;
-               return cinergyt2_ioctl(inode, file, FE_READ_STATUS,
-                                       (unsigned long) &e->status);
-       }
-
-       default:
-               ;
-       }
-
-       return -EINVAL;
-}
-
-static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       int ret = 0;
-
-       lock_kernel();
-
-       if (vma->vm_flags & (VM_WRITE | VM_EXEC)) {
-               ret = -EPERM;
-               goto bailout;
-       }
-
-       if (vma->vm_end > vma->vm_start + STREAM_URB_COUNT * STREAM_BUF_SIZE) {
-               ret = -EINVAL;
-               goto bailout;
-       }
-
-       vma->vm_flags |= (VM_IO | VM_DONTCOPY);
-       vma->vm_file = file;
-
-       ret = remap_pfn_range(vma, vma->vm_start,
-                             virt_to_phys(cinergyt2->streambuf) >> PAGE_SHIFT,
-                             vma->vm_end - vma->vm_start,
-                             vma->vm_page_prot) ? -EAGAIN : 0;
-bailout:
-       unlock_kernel();
-       return ret;
-}
-
-static struct file_operations cinergyt2_fops = {
-       .owner          = THIS_MODULE,
-       .ioctl          = cinergyt2_ioctl,
-       .poll           = cinergyt2_poll,
-       .open           = cinergyt2_open,
-       .release        = cinergyt2_release,
-       .mmap           = cinergyt2_mmap
-};
-
-static struct dvb_device cinergyt2_fe_template = {
-       .users = ~0,
-       .writers = 1,
-       .readers = (~0)-1,
-       .fops = &cinergyt2_fops
-};
-
-#ifdef ENABLE_RC
-
-static void cinergyt2_query_rc (struct work_struct *work)
-{
-       struct cinergyt2 *cinergyt2 =
-               container_of(work, struct cinergyt2, rc_query_work.work);
-       char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS };
-       struct cinergyt2_rc_event rc_events[12];
-       int n, len, i;
-
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
-               return;
-
-       len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
-                               (char *) rc_events, sizeof(rc_events));
-       if (len < 0)
-               goto out;
-       if (len == 0) {
-               if (time_after(jiffies, cinergyt2->last_event_jiffies +
-                              msecs_to_jiffies(150))) {
-                       /* stop key repeat */
-                       if (cinergyt2->rc_input_event != KEY_MAX) {
-                               dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event);
-                               input_report_key(cinergyt2->rc_input_dev,
-                                                cinergyt2->rc_input_event, 0);
-                               input_sync(cinergyt2->rc_input_dev);
-                               cinergyt2->rc_input_event = KEY_MAX;
-                       }
-                       cinergyt2->rc_last_code = cpu_to_le32(~0);
-               }
-               goto out;
-       }
-       cinergyt2->last_event_jiffies = jiffies;
-
-       for (n = 0; n < (len / sizeof(rc_events[0])); n++) {
-               dprintk(1, "rc_events[%d].value = %x, type=%x\n",
-                       n, le32_to_cpu(rc_events[n].value), rc_events[n].type);
-
-               if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC &&
-                   rc_events[n].value == cpu_to_le32(~0)) {
-                       /* keyrepeat bit -> just repeat last rc_input_event */
-               } else {
-                       cinergyt2->rc_input_event = KEY_MAX;
-                       for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) {
-                               if (rc_keys[i + 0] == rc_events[n].type &&
-                                   rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) {
-                                       cinergyt2->rc_input_event = rc_keys[i + 2];
-                                       break;
-                               }
-                       }
-               }
-
-               if (cinergyt2->rc_input_event != KEY_MAX) {
-                       if (rc_events[n].value == cinergyt2->rc_last_code &&
-                           cinergyt2->rc_last_code != cpu_to_le32(~0)) {
-                               /* emit a key-up so the double event is recognized */
-                               dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event);
-                               input_report_key(cinergyt2->rc_input_dev,
-                                                cinergyt2->rc_input_event, 0);
-                       }
-                       dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event);
-                       input_report_key(cinergyt2->rc_input_dev,
-                                        cinergyt2->rc_input_event, 1);
-                       input_sync(cinergyt2->rc_input_dev);
-                       cinergyt2->rc_last_code = rc_events[n].value;
-               }
-       }
-
-out:
-       schedule_delayed_work(&cinergyt2->rc_query_work,
-                             msecs_to_jiffies(RC_QUERY_INTERVAL));
-
-       mutex_unlock(&cinergyt2->sem);
-}
-
-static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
-{
-       struct input_dev *input_dev;
-       int i;
-       int err;
-
-       input_dev = input_allocate_device();
-       if (!input_dev)
-               return -ENOMEM;
-
-       usb_make_path(cinergyt2->udev, cinergyt2->phys, sizeof(cinergyt2->phys));
-       strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys));
-       cinergyt2->rc_input_event = KEY_MAX;
-       cinergyt2->rc_last_code = cpu_to_le32(~0);
-       INIT_DELAYED_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc);
-
-       input_dev->name = DRIVER_NAME " remote control";
-       input_dev->phys = cinergyt2->phys;
-       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-       for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3)
-               set_bit(rc_keys[i + 2], input_dev->keybit);
-       input_dev->keycodesize = 0;
-       input_dev->keycodemax = 0;
-       input_dev->id.bustype = BUS_USB;
-       input_dev->id.vendor = le16_to_cpu(cinergyt2->udev->descriptor.idVendor);
-       input_dev->id.product = le16_to_cpu(cinergyt2->udev->descriptor.idProduct);
-       input_dev->id.version = 1;
-       input_dev->dev.parent = &cinergyt2->udev->dev;
-
-       err = input_register_device(input_dev);
-       if (err) {
-               input_free_device(input_dev);
-               return err;
-       }
-
-       cinergyt2->rc_input_dev = input_dev;
-       schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
-
-       return 0;
-}
-
-static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2)
-{
-       cancel_rearming_delayed_work(&cinergyt2->rc_query_work);
-       input_unregister_device(cinergyt2->rc_input_dev);
-}
-
-static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2)
-{
-       cancel_rearming_delayed_work(&cinergyt2->rc_query_work);
-}
-
-static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2)
-{
-       schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
-}
-
-#else
-
-static inline int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) { return 0; }
-static inline void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { }
-static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) { }
-static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { }
-
-#endif /* ENABLE_RC */
-
-static void cinergyt2_query (struct work_struct *work)
-{
-       struct cinergyt2 *cinergyt2 =
-               container_of(work, struct cinergyt2, query_work.work);
-       char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS };
-       struct dvbt_get_status_msg *s = &cinergyt2->status;
-       uint8_t lock_bits;
-
-       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
-               return;
-
-       lock_bits = s->lock_bits;
-
-       cinergyt2_command(cinergyt2, cmd, sizeof(cmd), (char *) s, sizeof(*s));
-
-       cinergyt2->uncorrected_block_count +=
-               le32_to_cpu(s->uncorrected_block_count);
-
-       if (lock_bits != s->lock_bits) {
-               wake_up_interruptible(&cinergyt2->poll_wq);
-               cinergyt2->pending_fe_events++;
-       }
-
-       schedule_delayed_work(&cinergyt2->query_work,
-                             msecs_to_jiffies(QUERY_INTERVAL));
-
-       mutex_unlock(&cinergyt2->sem);
-}
-
-static int cinergyt2_probe (struct usb_interface *intf,
-                 const struct usb_device_id *id)
-{
-       struct cinergyt2 *cinergyt2;
-       int err;
-
-       if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
-               dprintk(1, "out of memory?!?\n");
-               return -ENOMEM;
-       }
-
-       usb_set_intfdata (intf, (void *) cinergyt2);
-
-       mutex_init(&cinergyt2->sem);
-       mutex_init(&cinergyt2->wq_sem);
-       init_waitqueue_head (&cinergyt2->poll_wq);
-       INIT_DELAYED_WORK(&cinergyt2->query_work, cinergyt2_query);
-
-       cinergyt2->udev = interface_to_usbdev(intf);
-       cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
-
-       if (cinergyt2_alloc_stream_urbs (cinergyt2) < 0) {
-               dprintk(1, "unable to allocate stream urbs\n");
-               kfree(cinergyt2);
-               return -ENOMEM;
-       }
-
-       err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME,
-                                  THIS_MODULE, &cinergyt2->udev->dev,
-                                  adapter_nr);
-       if (err < 0) {
-               kfree(cinergyt2);
-               return err;
-       }
-
-       cinergyt2->demux.priv = cinergyt2;
-       cinergyt2->demux.filternum = 256;
-       cinergyt2->demux.feednum = 256;
-       cinergyt2->demux.start_feed = cinergyt2_start_feed;
-       cinergyt2->demux.stop_feed = cinergyt2_stop_feed;
-       cinergyt2->demux.dmx.capabilities = DMX_TS_FILTERING |
-                                           DMX_SECTION_FILTERING |
-                                           DMX_MEMORY_BASED_FILTERING;
-
-       if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) {
-               dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err);
-               goto bailout;
-       }
-
-       cinergyt2->dmxdev.filternum = cinergyt2->demux.filternum;
-       cinergyt2->dmxdev.demux = &cinergyt2->demux.dmx;
-       cinergyt2->dmxdev.capabilities = 0;
-
-       if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, &cinergyt2->adapter)) < 0) {
-               dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err);
-               goto bailout;
-       }
-
-       if (dvb_net_init(&cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx))
-               dprintk(1, "dvb_net_init() failed!\n");
-
-       dvb_register_device(&cinergyt2->adapter, &cinergyt2->fedev,
-                           &cinergyt2_fe_template, cinergyt2,
-                           DVB_DEVICE_FRONTEND);
-
-       err = cinergyt2_register_rc(cinergyt2);
-       if (err)
-               goto bailout;
-
-       return 0;
-
-bailout:
-       dvb_net_release(&cinergyt2->dvbnet);
-       dvb_dmxdev_release(&cinergyt2->dmxdev);
-       dvb_dmx_release(&cinergyt2->demux);
-       dvb_unregister_adapter(&cinergyt2->adapter);
-       cinergyt2_free_stream_urbs(cinergyt2);
-       kfree(cinergyt2);
-       return -ENOMEM;
-}
-
-static void cinergyt2_disconnect (struct usb_interface *intf)
-{
-       struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
-
-       cinergyt2_unregister_rc(cinergyt2);
-       cancel_rearming_delayed_work(&cinergyt2->query_work);
-       wake_up_interruptible(&cinergyt2->poll_wq);
-
-       cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
-       cinergyt2->disconnect_pending = 1;
-
-       if (!atomic_read(&cinergyt2->inuse))
-               cinergyt2_unregister(cinergyt2);
-}
-
-static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
-{
-       struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
-
-       if (cinergyt2->disconnect_pending)
-               return -EAGAIN;
-       if (mutex_lock_interruptible(&cinergyt2->wq_sem))
-               return -ERESTARTSYS;
-
-       cinergyt2_suspend_rc(cinergyt2);
-       cancel_rearming_delayed_work(&cinergyt2->query_work);
-
-       mutex_lock(&cinergyt2->sem);
-       if (cinergyt2->streaming)
-               cinergyt2_stop_stream_xfer(cinergyt2);
-       cinergyt2_sleep(cinergyt2, 1);
-       mutex_unlock(&cinergyt2->sem);
-
-       mutex_unlock(&cinergyt2->wq_sem);
-
-       return 0;
-}
-
-static int cinergyt2_resume (struct usb_interface *intf)
-{
-       struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
-       struct dvbt_set_parameters_msg *param = &cinergyt2->param;
-       int err = -EAGAIN;
-
-       if (cinergyt2->disconnect_pending)
-               goto out;
-       err = mutex_lock_interruptible(&cinergyt2->wq_sem);
-       if (err)
-               goto out;
-
-       err = mutex_lock_interruptible(&cinergyt2->sem);
-       if (err)
-               goto out_unlock1;
-
-       if (!cinergyt2->sleeping) {
-               cinergyt2_sleep(cinergyt2, 0);
-               cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0);
-               if (cinergyt2->streaming)
-                       cinergyt2_start_stream_xfer(cinergyt2);
-               schedule_delayed_work(&cinergyt2->query_work, HZ/2);
-       }
-
-       cinergyt2_resume_rc(cinergyt2);
-
-       mutex_unlock(&cinergyt2->sem);
-out_unlock1:
-       mutex_unlock(&cinergyt2->wq_sem);
-out:
-       return err;
-}
-
-static const struct usb_device_id cinergyt2_table [] __devinitdata = {
-       { USB_DEVICE(0x0ccd, 0x0038) },
-       { 0 }
-};
-
-MODULE_DEVICE_TABLE(usb, cinergyt2_table);
-
-static struct usb_driver cinergyt2_driver = {
-       .name   = "cinergyT2",
-       .probe  = cinergyt2_probe,
-       .disconnect     = cinergyt2_disconnect,
-       .suspend        = cinergyt2_suspend,
-       .resume         = cinergyt2_resume,
-       .id_table       = cinergyt2_table
-};
-
-static int __init cinergyt2_init (void)
-{
-       int err;
-
-       if ((err = usb_register(&cinergyt2_driver)) < 0)
-               dprintk(1, "usb_register() failed! (err %i)\n", err);
-
-       return err;
-}
-
-static void __exit cinergyt2_exit (void)
-{
-       usb_deregister(&cinergyt2_driver);
-}
-
-module_init (cinergyt2_init);
-module_exit (cinergyt2_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
new file mode 100644 (file)
index 0000000..1332301
--- /dev/null
@@ -0,0 +1,18 @@
+config DVB_DM1105
+       tristate "SDMC DM1105 based PCI cards"
+       depends on DVB_CORE && PCI && I2C
+       select DVB_PLL if !DVB_FE_CUSTOMISE
+       select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_STV0288 if !DVB_FE_CUSTOMISE
+       select DVB_STB6000 if !DVB_FE_CUSTOMISE
+       select DVB_CX24116 if !DVB_FE_CUSTOMISE
+       select DVB_SI21XX if !DVB_FE_CUSTOMISE
+       help
+         Support for cards based on the SDMC DM1105 PCI chip like
+         DvbWorld 2002
+
+         Since these cards have no MPEG decoder onboard, they transmit
+         only compressed MPEG data over the PCI bus, so you need
+         an external software decoder to watch TV on your computer.
+
+         Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile
new file mode 100644 (file)
index 0000000..8ac28b0
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_DM1105) += dm1105.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
new file mode 100644 (file)
index 0000000..f732144
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip
+ *
+ * Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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/version.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/input.h>
+#include <media/ir-common.h>
+
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+#include "dvb-pll.h"
+
+#include "stv0299.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "si21xx.h"
+#include "cx24116.h"
+#include "z0194a.h"
+
+/* ----------------------------------------------- */
+/*
+ * PCI ID's
+ */
+#ifndef PCI_VENDOR_ID_TRIGEM
+#define PCI_VENDOR_ID_TRIGEM   0x109f
+#endif
+#ifndef PCI_DEVICE_ID_DM1105
+#define PCI_DEVICE_ID_DM1105   0x036f
+#endif
+#ifndef PCI_DEVICE_ID_DW2002
+#define PCI_DEVICE_ID_DW2002   0x2002
+#endif
+#ifndef PCI_DEVICE_ID_DW2004
+#define PCI_DEVICE_ID_DW2004   0x2004
+#endif
+/* ----------------------------------------------- */
+/* sdmc dm1105 registers */
+
+/* TS Control */
+#define DM1105_TSCTR                           0x00
+#define DM1105_DTALENTH                                0x04
+
+/* GPIO Interface */
+#define DM1105_GPIOVAL                         0x08
+#define DM1105_GPIOCTR                         0x0c
+
+/* PID serial number */
+#define DM1105_PIDN                            0x10
+
+/* Odd-even secret key select */
+#define DM1105_CWSEL                           0x14
+
+/* Host Command Interface */
+#define DM1105_HOST_CTR                                0x18
+#define DM1105_HOST_AD                         0x1c
+
+/* PCI Interface */
+#define DM1105_CR                              0x30
+#define DM1105_RST                             0x34
+#define DM1105_STADR                           0x38
+#define DM1105_RLEN                            0x3c
+#define DM1105_WRP                             0x40
+#define DM1105_INTCNT                          0x44
+#define DM1105_INTMAK                          0x48
+#define DM1105_INTSTS                          0x4c
+
+/* CW Value */
+#define DM1105_ODD                             0x50
+#define DM1105_EVEN                            0x58
+
+/* PID Value */
+#define DM1105_PID                             0x60
+
+/* IR Control */
+#define DM1105_IRCTR                           0x64
+#define DM1105_IRMODE                          0x68
+#define DM1105_SYSTEMCODE                      0x6c
+#define DM1105_IRCODE                          0x70
+
+/* Unknown Values */
+#define DM1105_ENCRYPT                         0x74
+#define DM1105_VER                             0x7c
+
+/* I2C Interface */
+#define DM1105_I2CCTR                          0x80
+#define DM1105_I2CSTS                          0x81
+#define DM1105_I2CDAT                          0x82
+#define DM1105_I2C_RA                          0x83
+/* ----------------------------------------------- */
+/* Interrupt Mask Bits */
+
+#define INTMAK_TSIRQM                          0x01
+#define INTMAK_HIRQM                           0x04
+#define INTMAK_IRM                             0x08
+#define INTMAK_ALLMASK                         (INTMAK_TSIRQM | \
+                                               INTMAK_HIRQM | \
+                                               INTMAK_IRM)
+#define INTMAK_NONEMASK                                0x00
+
+/* Interrupt Status Bits */
+#define INTSTS_TSIRQ                           0x01
+#define INTSTS_HIRQ                            0x04
+#define INTSTS_IR                              0x08
+
+/* IR Control Bits */
+#define DM1105_IR_EN                           0x01
+#define DM1105_SYS_CHK                         0x02
+#define DM1105_REP_FLG                         0x08
+
+/* EEPROM addr */
+#define IIC_24C01_addr                         0xa0
+/* Max board count */
+#define DM1105_MAX                             0x04
+
+#define DRIVER_NAME                            "dm1105"
+
+#define DM1105_DMA_PACKETS                     47
+#define DM1105_DMA_PACKET_LENGTH               (128*4)
+#define DM1105_DMA_BYTES                       (128 * 4 * DM1105_DMA_PACKETS)
+
+/* GPIO's for LNB power control */
+#define DM1105_LNB_MASK                                0x00000000
+#define DM1105_LNB_13V                         0x00010100
+#define DM1105_LNB_18V                         0x00000100
+
+static int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static u16 ir_codes_dm1105_nec[128] = {
+       [0x0a] = KEY_Q,         /*power*/
+       [0x0c] = KEY_M,         /*mute*/
+       [0x11] = KEY_1,
+       [0x12] = KEY_2,
+       [0x13] = KEY_3,
+       [0x14] = KEY_4,
+       [0x15] = KEY_5,
+       [0x16] = KEY_6,
+       [0x17] = KEY_7,
+       [0x18] = KEY_8,
+       [0x19] = KEY_9,
+       [0x10] = KEY_0,
+       [0x1c] = KEY_PAGEUP,    /*ch+*/
+       [0x0f] = KEY_PAGEDOWN,  /*ch-*/
+       [0x1a] = KEY_O,         /*vol+*/
+       [0x0e] = KEY_Z,         /*vol-*/
+       [0x04] = KEY_R,         /*rec*/
+       [0x09] = KEY_D,         /*fav*/
+       [0x08] = KEY_BACKSPACE, /*rewind*/
+       [0x07] = KEY_A,         /*fast*/
+       [0x0b] = KEY_P,         /*pause*/
+       [0x02] = KEY_ESC,       /*cancel*/
+       [0x03] = KEY_G,         /*tab*/
+       [0x00] = KEY_UP,        /*up*/
+       [0x1f] = KEY_ENTER,     /*ok*/
+       [0x01] = KEY_DOWN,      /*down*/
+       [0x05] = KEY_C,         /*cap*/
+       [0x06] = KEY_S,         /*stop*/
+       [0x40] = KEY_F,         /*full*/
+       [0x1e] = KEY_W,         /*tvmode*/
+       [0x1b] = KEY_B,         /*recall*/
+};
+
+/* infrared remote control */
+struct infrared {
+       u16     key_map[128];
+       struct input_dev        *input_dev;
+       char                    input_phys[32];
+       struct tasklet_struct   ir_tasklet;
+       u32                     ir_command;
+};
+
+struct dm1105dvb {
+       /* pci */
+       struct pci_dev *pdev;
+       u8 __iomem *io_mem;
+
+       /* ir */
+       struct infrared ir;
+
+       /* dvb */
+       struct dmx_frontend hw_frontend;
+       struct dmx_frontend mem_frontend;
+       struct dmxdev dmxdev;
+       struct dvb_adapter dvb_adapter;
+       struct dvb_demux demux;
+       struct dvb_frontend *fe;
+       struct dvb_net dvbnet;
+       unsigned int full_ts_users;
+
+       /* i2c */
+       struct i2c_adapter i2c_adap;
+
+       /* dma */
+       dma_addr_t dma_addr;
+       unsigned char *ts_buf;
+       u32 wrp;
+       u32 buffer_size;
+       unsigned int    PacketErrorCount;
+       unsigned int dmarst;
+       spinlock_t lock;
+
+};
+
+#define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
+
+static struct dm1105dvb *dm1105dvb_local;
+
+static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
+                           struct i2c_msg *msgs, int num)
+{
+       struct dm1105dvb *dm1105dvb ;
+
+       int addr, rc, i, j, k, len, byte, data;
+       u8 status;
+
+       dm1105dvb = i2c_adap->algo_data;
+       for (i = 0; i < num; i++) {
+               outb(0x00, dm_io_mem(DM1105_I2CCTR));
+               if (msgs[i].flags & I2C_M_RD) {
+                       /* read bytes */
+                       addr  = msgs[i].addr << 1;
+                       addr |= 1;
+                       outb(addr, dm_io_mem(DM1105_I2CDAT));
+                       for (byte = 0; byte < msgs[i].len; byte++)
+                               outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1));
+
+                       outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+                       for (j = 0; j < 55; j++) {
+                               mdelay(10);
+                               status = inb(dm_io_mem(DM1105_I2CSTS));
+                               if ((status & 0xc0) == 0x40)
+                                       break;
+                       }
+                       if (j >= 55)
+                               return -1;
+
+                       for (byte = 0; byte < msgs[i].len; byte++) {
+                               rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1));
+                               if (rc < 0)
+                                       goto err;
+                               msgs[i].buf[byte] = rc;
+                       }
+               } else {
+                       if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
+                               /* prepaired for cx24116 firmware */
+                               /* Write in small blocks */
+                               len = msgs[i].len - 1;
+                               k = 1;
+                               do {
+                                       outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT));
+                                       outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1));
+                                       for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
+                                               data = msgs[i].buf[k+byte];
+                                               outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2));
+                                       }
+                                       outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR));
+                                       for (j = 0; j < 25; j++) {
+                                               mdelay(10);
+                                               status = inb(dm_io_mem(DM1105_I2CSTS));
+                                               if ((status & 0xc0) == 0x40)
+                                                       break;
+                                       }
+
+                                       if (j >= 25)
+                                               return -1;
+
+                                       k += 48;
+                                       len -= 48;
+                               } while (len > 0);
+                       } else {
+                               /* write bytes */
+                               outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT));
+                               for (byte = 0; byte < msgs[i].len; byte++) {
+                                       data = msgs[i].buf[byte];
+                                       outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1));
+                               }
+                               outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+                               for (j = 0; j < 25; j++) {
+                                       mdelay(10);
+                                       status = inb(dm_io_mem(DM1105_I2CSTS));
+                                       if ((status & 0xc0) == 0x40)
+                                               break;
+                               }
+
+                               if (j >= 25)
+                                       return -1;
+                       }
+               }
+       }
+       return num;
+ err:
+       return rc;
+}
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dm1105_algo = {
+       .master_xfer   = dm1105_i2c_xfer,
+       .functionality = functionality,
+};
+
+static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed)
+{
+       return container_of(feed->demux, struct dm1105dvb, demux);
+}
+
+static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
+{
+       return container_of(fe->dvb, struct dm1105dvb, dvb_adapter);
+}
+
+static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
+
+               if (voltage == SEC_VOLTAGE_18) {
+                       outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
+                       outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL));
+               } else  {
+               /*LNB ON-13V by default!*/
+                       outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
+                       outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL));
+               }
+
+       return 0;
+}
+
+static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb)
+{
+       outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR));
+}
+
+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);
+}
+
+static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
+{
+       pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr);
+}
+
+static void __devinit dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb)
+{
+       outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK));
+       outb(1, dm_io_mem(DM1105_CR));
+}
+
+static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb)
+{
+       outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK));
+       outb(0, dm_io_mem(DM1105_CR));
+}
+
+static int dm1105dvb_start_feed(struct dvb_demux_feed *f)
+{
+       struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+
+       if (dm1105dvb->full_ts_users++ == 0)
+               dm1105dvb_enable_irqs(dm1105dvb);
+
+       return 0;
+}
+
+static int dm1105dvb_stop_feed(struct dvb_demux_feed *f)
+{
+       struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+
+       if (--dm1105dvb->full_ts_users == 0)
+               dm1105dvb_disable_irqs(dm1105dvb);
+
+       return 0;
+}
+
+/* ir tasklet */
+static void dm1105_emit_key(unsigned long parm)
+{
+       struct infrared *ir = (struct infrared *) parm;
+       u32 ircom = ir->ir_command;
+       u8 data;
+       u16 keycode;
+
+       data = (ircom >> 8) & 0x7f;
+
+       input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data);
+       input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
+       keycode = ir->key_map[data];
+
+       if (!keycode)
+               return;
+
+       input_event(ir->input_dev, EV_KEY, keycode, 1);
+       input_sync(ir->input_dev);
+       input_event(ir->input_dev, EV_KEY, keycode, 0);
+       input_sync(ir->input_dev);
+
+}
+
+static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
+{
+       struct dm1105dvb *dm1105dvb = dev_id;
+       unsigned int piece;
+       unsigned int nbpackets;
+       u32 command;
+       u32 nextwrp;
+       u32 oldwrp;
+
+       /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
+       unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
+       outb(intsts, dm_io_mem(DM1105_INTSTS));
+
+       switch (intsts) {
+       case INTSTS_TSIRQ:
+       case (INTSTS_TSIRQ | INTSTS_IR):
+               nextwrp = inl(dm_io_mem(DM1105_WRP)) -
+                       inl(dm_io_mem(DM1105_STADR)) ;
+               oldwrp = dm1105dvb->wrp;
+               spin_lock(&dm1105dvb->lock);
+               if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
+                               (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
+                               (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
+                       dm1105dvb->PacketErrorCount++;
+                       /* bad packet found */
+                       if ((dm1105dvb->PacketErrorCount >= 2) &&
+                                       (dm1105dvb->dmarst == 0)) {
+                               outb(1, dm_io_mem(DM1105_RST));
+                               dm1105dvb->wrp = 0;
+                               dm1105dvb->PacketErrorCount = 0;
+                               dm1105dvb->dmarst = 0;
+                               spin_unlock(&dm1105dvb->lock);
+                               return IRQ_HANDLED;
+                       }
+               }
+               if (nextwrp < oldwrp) {
+                       piece = dm1105dvb->buffer_size - oldwrp;
+                       memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp);
+                       nbpackets = (piece + nextwrp)/188;
+               } else  {
+                       nbpackets = (nextwrp - oldwrp)/188;
+               }
+               dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets);
+               dm1105dvb->wrp = nextwrp;
+               spin_unlock(&dm1105dvb->lock);
+               break;
+       case INTSTS_IR:
+               command = inl(dm_io_mem(DM1105_IRCODE));
+               if (ir_debug)
+                       printk("dm1105: received byte 0x%04x\n", command);
+
+               dm1105dvb->ir.ir_command = command;
+               tasklet_schedule(&dm1105dvb->ir.ir_tasklet);
+               break;
+       }
+       return IRQ_HANDLED;
+
+
+}
+
+/* register with input layer */
+static void input_register_keys(struct infrared *ir)
+{
+       int i;
+
+       memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
+
+       for (i = 0; i < ARRAY_SIZE(ir->key_map); i++)
+                       set_bit(ir->key_map[i], ir->input_dev->keybit);
+
+       ir->input_dev->keycode = ir->key_map;
+       ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
+       ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
+}
+
+int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
+{
+       struct input_dev *input_dev;
+       int err;
+
+       dm1105dvb_local = dm1105;
+
+       input_dev = input_allocate_device();
+       if (!input_dev)
+               return -ENOMEM;
+
+       dm1105->ir.input_dev = input_dev;
+       snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
+               "pci-%s/ir0", pci_name(dm1105->pdev));
+
+       input_dev->evbit[0] = BIT(EV_KEY);
+       input_dev->name = "DVB on-card IR receiver";
+
+       input_dev->phys = dm1105->ir.input_phys;
+       input_dev->id.bustype = BUS_PCI;
+       input_dev->id.version = 2;
+       if (dm1105->pdev->subsystem_vendor) {
+               input_dev->id.vendor = dm1105->pdev->subsystem_vendor;
+               input_dev->id.product = dm1105->pdev->subsystem_device;
+       } else {
+               input_dev->id.vendor = dm1105->pdev->vendor;
+               input_dev->id.product = dm1105->pdev->device;
+       }
+       input_dev->dev.parent = &dm1105->pdev->dev;
+       /* initial keymap */
+       memcpy(dm1105->ir.key_map, ir_codes_dm1105_nec, sizeof dm1105->ir.key_map);
+       input_register_keys(&dm1105->ir);
+       err = input_register_device(input_dev);
+       if (err) {
+               input_free_device(input_dev);
+               return err;
+       }
+
+       tasklet_init(&dm1105->ir.ir_tasklet, dm1105_emit_key, (unsigned long) &dm1105->ir);
+
+       return 0;
+}
+
+
+void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
+{
+       tasklet_kill(&dm1105->ir.ir_tasklet);
+       input_unregister_device(dm1105->ir.input_dev);
+
+}
+
+static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)
+{
+       dm1105dvb_disable_irqs(dm1105dvb);
+
+       outb(0, dm_io_mem(DM1105_HOST_CTR));
+
+       /*DATALEN 188,*/
+       outb(188, dm_io_mem(DM1105_DTALENTH));
+       /*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
+       outw(0xc10a, dm_io_mem(DM1105_TSCTR));
+
+       /* map DMA and set address */
+       dm1105dvb_dma_map(dm1105dvb);
+       dm1105dvb_set_dma_addr(dm1105dvb);
+       /* big buffer */
+       outl(5*DM1105_DMA_BYTES, dm_io_mem(DM1105_RLEN));
+       outb(47, dm_io_mem(DM1105_INTCNT));
+
+       /* IR NEC mode enable */
+       outb((DM1105_IR_EN | DM1105_SYS_CHK), dm_io_mem(DM1105_IRCTR));
+       outb(0, dm_io_mem(DM1105_IRMODE));
+       outw(0, dm_io_mem(DM1105_SYSTEMCODE));
+
+       return 0;
+}
+
+static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb)
+{
+       dm1105dvb_disable_irqs(dm1105dvb);
+
+       /* IR disable */
+       outb(0, dm_io_mem(DM1105_IRCTR));
+       outb(INTMAK_NONEMASK, dm_io_mem(DM1105_INTMAK));
+
+       dm1105dvb_dma_unmap(dm1105dvb);
+}
+
+static struct stv0288_config earda_config = {
+       .demod_address = 0x68,
+       .min_delay_ms = 100,
+};
+
+static struct si21xx_config serit_config = {
+       .demod_address = 0x68,
+       .min_delay_ms = 100,
+
+};
+
+static struct cx24116_config serit_sp2633_config = {
+       .demod_address = 0x55,
+};
+
+static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
+{
+       int ret;
+
+       switch (dm1105dvb->pdev->subsystem_device) {
+       case PCI_DEVICE_ID_DW2002:
+               dm1105dvb->fe = dvb_attach(
+                       stv0299_attach, &sharp_z0194a_config,
+                       &dm1105dvb->i2c_adap);
+
+               if (dm1105dvb->fe) {
+                       dm1105dvb->fe->ops.set_voltage =
+                                                       dm1105dvb_set_voltage;
+                       dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
+                                       &dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
+               }
+
+               if (!dm1105dvb->fe) {
+                       dm1105dvb->fe = dvb_attach(
+                               stv0288_attach, &earda_config,
+                               &dm1105dvb->i2c_adap);
+                       if (dm1105dvb->fe) {
+                               dm1105dvb->fe->ops.set_voltage =
+                                                       dm1105dvb_set_voltage;
+                               dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
+                                               &dm1105dvb->i2c_adap);
+                       }
+               }
+
+               if (!dm1105dvb->fe) {
+                       dm1105dvb->fe = dvb_attach(
+                               si21xx_attach, &serit_config,
+                               &dm1105dvb->i2c_adap);
+                       if (dm1105dvb->fe)
+                               dm1105dvb->fe->ops.set_voltage =
+                                                       dm1105dvb_set_voltage;
+               }
+               break;
+       case PCI_DEVICE_ID_DW2004:
+               dm1105dvb->fe = dvb_attach(
+                       cx24116_attach, &serit_sp2633_config,
+                       &dm1105dvb->i2c_adap);
+               if (dm1105dvb->fe)
+                       dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
+               break;
+       }
+
+       if (!dm1105dvb->fe) {
+               dev_err(&dm1105dvb->pdev->dev, "could not attach frontend\n");
+               return -ENODEV;
+       }
+
+       ret = dvb_register_frontend(&dm1105dvb->dvb_adapter, dm1105dvb->fe);
+       if (ret < 0) {
+               if (dm1105dvb->fe->ops.release)
+                       dm1105dvb->fe->ops.release(dm1105dvb->fe);
+               dm1105dvb->fe = NULL;
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
+{
+       static u8 command[1] = { 0x28 };
+
+       struct i2c_msg msg[] = {
+               { .addr = IIC_24C01_addr >> 1, .flags = 0,
+                               .buf = command, .len = 1 },
+               { .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD,
+                               .buf = mac, .len = 6 },
+       };
+
+       dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
+       dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int __devinit dm1105_probe(struct pci_dev *pdev,
+                                 const struct pci_device_id *ent)
+{
+       struct dm1105dvb *dm1105dvb;
+       struct dvb_adapter *dvb_adapter;
+       struct dvb_demux *dvbdemux;
+       struct dmx_demux *dmx;
+       int ret = -ENOMEM;
+
+       dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
+       if (!dm1105dvb)
+               goto out;
+
+       dm1105dvb->pdev = pdev;
+       dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
+       dm1105dvb->PacketErrorCount = 0;
+       dm1105dvb->dmarst = 0;
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0)
+               goto err_kfree;
+
+       ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       if (ret < 0)
+               goto err_pci_disable_device;
+
+       pci_set_master(pdev);
+
+       ret = pci_request_regions(pdev, DRIVER_NAME);
+       if (ret < 0)
+               goto err_pci_disable_device;
+
+       dm1105dvb->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+       if (!dm1105dvb->io_mem) {
+               ret = -EIO;
+               goto err_pci_release_regions;
+       }
+
+       spin_lock_init(&dm1105dvb->lock);
+       pci_set_drvdata(pdev, dm1105dvb);
+
+       ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb);
+       if (ret < 0)
+               goto err_pci_iounmap;
+
+       ret = dm1105dvb_hw_init(dm1105dvb);
+       if (ret < 0)
+               goto err_free_irq;
+
+       /* i2c */
+       i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
+       strcpy(dm1105dvb->i2c_adap.name, DRIVER_NAME);
+       dm1105dvb->i2c_adap.owner = THIS_MODULE;
+       dm1105dvb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+       dm1105dvb->i2c_adap.dev.parent = &pdev->dev;
+       dm1105dvb->i2c_adap.algo = &dm1105_algo;
+       dm1105dvb->i2c_adap.algo_data = dm1105dvb;
+       ret = i2c_add_adapter(&dm1105dvb->i2c_adap);
+
+       if (ret < 0)
+               goto err_dm1105dvb_hw_exit;
+
+       /* dvb */
+       ret = dvb_register_adapter(&dm1105dvb->dvb_adapter, DRIVER_NAME,
+                                       THIS_MODULE, &pdev->dev, adapter_nr);
+       if (ret < 0)
+               goto err_i2c_del_adapter;
+
+       dvb_adapter = &dm1105dvb->dvb_adapter;
+
+       dm1105dvb_read_mac(dm1105dvb, dvb_adapter->proposed_mac);
+
+       dvbdemux = &dm1105dvb->demux;
+       dvbdemux->filternum = 256;
+       dvbdemux->feednum = 256;
+       dvbdemux->start_feed = dm1105dvb_start_feed;
+       dvbdemux->stop_feed = dm1105dvb_stop_feed;
+       dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+                       DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+       ret = dvb_dmx_init(dvbdemux);
+       if (ret < 0)
+               goto err_dvb_unregister_adapter;
+
+       dmx = &dvbdemux->dmx;
+       dm1105dvb->dmxdev.filternum = 256;
+       dm1105dvb->dmxdev.demux = dmx;
+       dm1105dvb->dmxdev.capabilities = 0;
+
+       ret = dvb_dmxdev_init(&dm1105dvb->dmxdev, dvb_adapter);
+       if (ret < 0)
+               goto err_dvb_dmx_release;
+
+       dm1105dvb->hw_frontend.source = DMX_FRONTEND_0;
+
+       ret = dmx->add_frontend(dmx, &dm1105dvb->hw_frontend);
+       if (ret < 0)
+               goto err_dvb_dmxdev_release;
+
+       dm1105dvb->mem_frontend.source = DMX_MEMORY_FE;
+
+       ret = dmx->add_frontend(dmx, &dm1105dvb->mem_frontend);
+       if (ret < 0)
+               goto err_remove_hw_frontend;
+
+       ret = dmx->connect_frontend(dmx, &dm1105dvb->hw_frontend);
+       if (ret < 0)
+               goto err_remove_mem_frontend;
+
+       ret = frontend_init(dm1105dvb);
+       if (ret < 0)
+               goto err_disconnect_frontend;
+
+       dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
+       dm1105_ir_init(dm1105dvb);
+out:
+       return ret;
+
+err_disconnect_frontend:
+       dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+       dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
+err_remove_hw_frontend:
+       dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
+err_dvb_dmxdev_release:
+       dvb_dmxdev_release(&dm1105dvb->dmxdev);
+err_dvb_dmx_release:
+       dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+       dvb_unregister_adapter(dvb_adapter);
+err_i2c_del_adapter:
+       i2c_del_adapter(&dm1105dvb->i2c_adap);
+err_dm1105dvb_hw_exit:
+       dm1105dvb_hw_exit(dm1105dvb);
+err_free_irq:
+       free_irq(pdev->irq, dm1105dvb);
+err_pci_iounmap:
+       pci_iounmap(pdev, dm1105dvb->io_mem);
+err_pci_release_regions:
+       pci_release_regions(pdev);
+err_pci_disable_device:
+       pci_disable_device(pdev);
+err_kfree:
+       pci_set_drvdata(pdev, NULL);
+       kfree(dm1105dvb);
+       goto out;
+}
+
+static void __devexit dm1105_remove(struct pci_dev *pdev)
+{
+       struct dm1105dvb *dm1105dvb = pci_get_drvdata(pdev);
+       struct dvb_adapter *dvb_adapter = &dm1105dvb->dvb_adapter;
+       struct dvb_demux *dvbdemux = &dm1105dvb->demux;
+       struct dmx_demux *dmx = &dvbdemux->dmx;
+
+       dm1105_ir_exit(dm1105dvb);
+       dmx->close(dmx);
+       dvb_net_release(&dm1105dvb->dvbnet);
+       if (dm1105dvb->fe)
+               dvb_unregister_frontend(dm1105dvb->fe);
+
+       dmx->disconnect_frontend(dmx);
+       dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
+       dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
+       dvb_dmxdev_release(&dm1105dvb->dmxdev);
+       dvb_dmx_release(dvbdemux);
+       dvb_unregister_adapter(dvb_adapter);
+       if (&dm1105dvb->i2c_adap)
+               i2c_del_adapter(&dm1105dvb->i2c_adap);
+
+       dm1105dvb_hw_exit(dm1105dvb);
+       synchronize_irq(pdev->irq);
+       free_irq(pdev->irq, dm1105dvb);
+       pci_iounmap(pdev, dm1105dvb->io_mem);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       kfree(dm1105dvb);
+}
+
+static struct pci_device_id dm1105_id_table[] __devinitdata = {
+       {
+               .vendor = PCI_VENDOR_ID_TRIGEM,
+               .device = PCI_DEVICE_ID_DM1105,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_DEVICE_ID_DW2002,
+       }, {
+               .vendor = PCI_VENDOR_ID_TRIGEM,
+               .device = PCI_DEVICE_ID_DM1105,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_DEVICE_ID_DW2004,
+       }, {
+               /* empty */
+       },
+};
+
+MODULE_DEVICE_TABLE(pci, dm1105_id_table);
+
+static struct pci_driver dm1105_driver = {
+       .name = DRIVER_NAME,
+       .id_table = dm1105_id_table,
+       .probe = dm1105_probe,
+       .remove = __devexit_p(dm1105_remove),
+};
+
+static int __init dm1105_init(void)
+{
+       return pci_register_driver(&dm1105_driver);
+}
+
+static void __exit dm1105_exit(void)
+{
+       pci_unregister_driver(&dm1105_driver);
+}
+
+module_init(dm1105_init);
+module_exit(dm1105_exit);
+
+MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
+MODULE_DESCRIPTION("SDMC DM1105 DVB driver");
+MODULE_LICENSE("GPL");
index 3526e3e..f170e82 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "dvb_frontend.h"
 #include "dvbdev.h"
+#include <linux/dvb/version.h>
 
 static int dvb_frontend_debug;
 static int dvb_shutdown_timeout;
@@ -755,6 +756,539 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
        return 0;
 }
 
+struct dtv_cmds_h dtv_cmds[] = {
+       [DTV_TUNE] = {
+               .name   = "DTV_TUNE",
+               .cmd    = DTV_TUNE,
+               .set    = 1,
+       },
+       [DTV_CLEAR] = {
+               .name   = "DTV_CLEAR",
+               .cmd    = DTV_CLEAR,
+               .set    = 1,
+       },
+
+       /* Set */
+       [DTV_FREQUENCY] = {
+               .name   = "DTV_FREQUENCY",
+               .cmd    = DTV_FREQUENCY,
+               .set    = 1,
+       },
+       [DTV_BANDWIDTH_HZ] = {
+               .name   = "DTV_BANDWIDTH_HZ",
+               .cmd    = DTV_BANDWIDTH_HZ,
+               .set    = 1,
+       },
+       [DTV_MODULATION] = {
+               .name   = "DTV_MODULATION",
+               .cmd    = DTV_MODULATION,
+               .set    = 1,
+       },
+       [DTV_INVERSION] = {
+               .name   = "DTV_INVERSION",
+               .cmd    = DTV_INVERSION,
+               .set    = 1,
+       },
+       [DTV_DISEQC_MASTER] = {
+               .name   = "DTV_DISEQC_MASTER",
+               .cmd    = DTV_DISEQC_MASTER,
+               .set    = 1,
+               .buffer = 1,
+       },
+       [DTV_SYMBOL_RATE] = {
+               .name   = "DTV_SYMBOL_RATE",
+               .cmd    = DTV_SYMBOL_RATE,
+               .set    = 1,
+       },
+       [DTV_INNER_FEC] = {
+               .name   = "DTV_INNER_FEC",
+               .cmd    = DTV_INNER_FEC,
+               .set    = 1,
+       },
+       [DTV_VOLTAGE] = {
+               .name   = "DTV_VOLTAGE",
+               .cmd    = DTV_VOLTAGE,
+               .set    = 1,
+       },
+       [DTV_TONE] = {
+               .name   = "DTV_TONE",
+               .cmd    = DTV_TONE,
+               .set    = 1,
+       },
+       [DTV_PILOT] = {
+               .name   = "DTV_PILOT",
+               .cmd    = DTV_PILOT,
+               .set    = 1,
+       },
+       [DTV_ROLLOFF] = {
+               .name   = "DTV_ROLLOFF",
+               .cmd    = DTV_ROLLOFF,
+               .set    = 1,
+       },
+       [DTV_DELIVERY_SYSTEM] = {
+               .name   = "DTV_DELIVERY_SYSTEM",
+               .cmd    = DTV_DELIVERY_SYSTEM,
+               .set    = 1,
+       },
+       [DTV_HIERARCHY] = {
+               .name   = "DTV_HIERARCHY",
+               .cmd    = DTV_HIERARCHY,
+               .set    = 1,
+       },
+       [DTV_CODE_RATE_HP] = {
+               .name   = "DTV_CODE_RATE_HP",
+               .cmd    = DTV_CODE_RATE_HP,
+               .set    = 1,
+       },
+       [DTV_CODE_RATE_LP] = {
+               .name   = "DTV_CODE_RATE_LP",
+               .cmd    = DTV_CODE_RATE_LP,
+               .set    = 1,
+       },
+       [DTV_GUARD_INTERVAL] = {
+               .name   = "DTV_GUARD_INTERVAL",
+               .cmd    = DTV_GUARD_INTERVAL,
+               .set    = 1,
+       },
+       [DTV_TRANSMISSION_MODE] = {
+               .name   = "DTV_TRANSMISSION_MODE",
+               .cmd    = DTV_TRANSMISSION_MODE,
+               .set    = 1,
+       },
+       /* Get */
+       [DTV_DISEQC_SLAVE_REPLY] = {
+               .name   = "DTV_DISEQC_SLAVE_REPLY",
+               .cmd    = DTV_DISEQC_SLAVE_REPLY,
+               .set    = 0,
+               .buffer = 1,
+       },
+       [DTV_API_VERSION] = {
+               .name   = "DTV_API_VERSION",
+               .cmd    = DTV_API_VERSION,
+               .set    = 0,
+       },
+       [DTV_CODE_RATE_HP] = {
+               .name   = "DTV_CODE_RATE_HP",
+               .cmd    = DTV_CODE_RATE_HP,
+               .set    = 0,
+       },
+       [DTV_CODE_RATE_LP] = {
+               .name   = "DTV_CODE_RATE_LP",
+               .cmd    = DTV_CODE_RATE_LP,
+               .set    = 0,
+       },
+       [DTV_GUARD_INTERVAL] = {
+               .name   = "DTV_GUARD_INTERVAL",
+               .cmd    = DTV_GUARD_INTERVAL,
+               .set    = 0,
+       },
+       [DTV_TRANSMISSION_MODE] = {
+               .name   = "DTV_TRANSMISSION_MODE",
+               .cmd    = DTV_TRANSMISSION_MODE,
+               .set    = 0,
+       },
+       [DTV_HIERARCHY] = {
+               .name   = "DTV_HIERARCHY",
+               .cmd    = DTV_HIERARCHY,
+               .set    = 0,
+       },
+};
+
+void dtv_property_dump(struct dtv_property *tvp)
+{
+       int i;
+
+       if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
+               printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n",
+                       __func__, tvp->cmd);
+               return;
+       }
+
+       printk("%s() tvp.cmd    = 0x%08x (%s)\n"
+               ,__FUNCTION__
+               ,tvp->cmd
+               ,dtv_cmds[ tvp->cmd ].name);
+
+       if(dtv_cmds[ tvp->cmd ].buffer) {
+
+               printk("%s() tvp.u.buffer.len = 0x%02x\n"
+                       ,__FUNCTION__
+                       ,tvp->u.buffer.len);
+
+               for(i = 0; i < tvp->u.buffer.len; i++)
+                       printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+                               ,__FUNCTION__
+                               ,i
+                               ,tvp->u.buffer.data[i]);
+
+       } else
+               printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
+}
+
+int is_legacy_delivery_system(fe_delivery_system_t s)
+{
+       if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
+               (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS))
+               return 1;
+
+       return 0;
+}
+
+/* Synchronise the legacy tuning parameters into the cache, so that demodulator
+ * drivers can use a single set_frontend tuning function, regardless of whether
+ * it's being used for the legacy or new API, reducing code and complexity.
+ */
+void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       printk("%s()\n", __FUNCTION__);
+
+       c->frequency = p->frequency;
+       c->inversion = p->inversion;
+
+       switch (fe->ops.info.type) {
+       case FE_QPSK:
+               c->modulation = QPSK;   /* implied for DVB-S in legacy API */
+               c->rolloff = ROLLOFF_35;/* implied for DVB-S */
+               c->symbol_rate = p->u.qpsk.symbol_rate;
+               c->fec_inner = p->u.qpsk.fec_inner;
+               c->delivery_system = SYS_DVBS;
+               break;
+       case FE_QAM:
+               c->symbol_rate = p->u.qam.symbol_rate;
+               c->fec_inner = p->u.qam.fec_inner;
+               c->modulation = p->u.qam.modulation;
+               c->delivery_system = SYS_DVBC_ANNEX_AC;
+               break;
+       case FE_OFDM:
+               if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+                       c->bandwidth_hz = 6000000;
+               else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+                       c->bandwidth_hz = 7000000;
+               else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+                       c->bandwidth_hz = 8000000;
+               else
+                       /* Including BANDWIDTH_AUTO */
+                       c->bandwidth_hz = 0;
+               c->code_rate_HP = p->u.ofdm.code_rate_HP;
+               c->code_rate_LP = p->u.ofdm.code_rate_LP;
+               c->modulation = p->u.ofdm.constellation;
+               c->transmission_mode = p->u.ofdm.transmission_mode;
+               c->guard_interval = p->u.ofdm.guard_interval;
+               c->hierarchy = p->u.ofdm.hierarchy_information;
+               c->delivery_system = SYS_DVBT;
+               break;
+       case FE_ATSC:
+               c->modulation = p->u.vsb.modulation;
+               if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+                       c->delivery_system = SYS_ATSC;
+               else
+                       c->delivery_system = SYS_DVBC_ANNEX_B;
+               break;
+       }
+}
+
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the advanced tuning API.
+ */
+void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_frontend_parameters *p = &fepriv->parameters;
+
+       printk("%s()\n", __FUNCTION__);
+
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+
+       switch (fe->ops.info.type) {
+       case FE_QPSK:
+               printk("%s() Preparing QPSK req\n", __FUNCTION__);
+               p->u.qpsk.symbol_rate = c->symbol_rate;
+               p->u.qpsk.fec_inner = c->fec_inner;
+               c->delivery_system = SYS_DVBS;
+               break;
+       case FE_QAM:
+               printk("%s() Preparing QAM req\n", __FUNCTION__);
+               p->u.qam.symbol_rate = c->symbol_rate;
+               p->u.qam.fec_inner = c->fec_inner;
+               p->u.qam.modulation = c->modulation;
+               c->delivery_system = SYS_DVBC_ANNEX_AC;
+               break;
+       case FE_OFDM:
+               printk("%s() Preparing OFDM req\n", __FUNCTION__);
+               if (c->bandwidth_hz == 6000000)
+                       p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+               else if (c->bandwidth_hz == 7000000)
+                       p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+               else if (c->bandwidth_hz == 8000000)
+                       p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+               else
+                       p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+               p->u.ofdm.code_rate_HP = c->code_rate_HP;
+               p->u.ofdm.code_rate_LP = c->code_rate_LP;
+               p->u.ofdm.constellation = c->modulation;
+               p->u.ofdm.transmission_mode = c->transmission_mode;
+               p->u.ofdm.guard_interval = c->guard_interval;
+               p->u.ofdm.hierarchy_information = c->hierarchy;
+               c->delivery_system = SYS_DVBT;
+               break;
+       case FE_ATSC:
+               printk("%s() Preparing VSB req\n", __FUNCTION__);
+               p->u.vsb.modulation = c->modulation;
+               if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+                       c->delivery_system = SYS_ATSC;
+               else
+                       c->delivery_system = SYS_DVBC_ANNEX_B;
+               break;
+       }
+}
+
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the legacy tuning API.
+ */
+void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_frontend_parameters *p = &fepriv->parameters;
+
+       printk("%s()\n", __FUNCTION__);
+
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+
+       switch(c->modulation) {
+       case PSK_8:
+       case APSK_16:
+       case QPSK:
+               p->u.qpsk.symbol_rate = c->symbol_rate;
+               p->u.qpsk.fec_inner = c->fec_inner;
+               break;
+       default:
+               break;
+       }
+
+       if(c->delivery_system == SYS_ISDBT) {
+               /* Fake out a generic DVB-T request so we pass validation in the ioctl */
+               p->frequency = c->frequency;
+               p->inversion = INVERSION_AUTO;
+               p->u.ofdm.constellation = QAM_AUTO;
+               p->u.ofdm.code_rate_HP = FEC_AUTO;
+               p->u.ofdm.code_rate_LP = FEC_AUTO;
+               p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+               p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+               p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+               p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
+       }
+}
+
+void dtv_property_cache_submit(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       printk("%s()\n", __FUNCTION__);
+
+       /* For legacy delivery systems we don't need the delivery_system to
+        * be specified, but we populate the older structures from the cache
+        * so we can call set_frontend on older drivers.
+        */
+       if(is_legacy_delivery_system(c->delivery_system)) {
+
+               printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation);
+               dtv_property_legacy_params_sync(fe);
+
+       } else {
+               printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation);
+
+               /* For advanced delivery systems / modulation types ...
+                * we seed the lecacy dvb_frontend_parameters structure
+                * so that the sanity checking code later in the IOCTL processing
+                * can validate our basic frequency ranges, symbolrates, modulation
+                * etc.
+                */
+               dtv_property_adv_params_sync(fe);
+       }
+}
+
+static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
+                       unsigned int cmd, void *parg);
+static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
+                       unsigned int cmd, void *parg);
+
+int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
+       struct inode *inode, struct file *file)
+{
+       int r = 0;
+
+       printk("%s()\n", __FUNCTION__);
+
+       dtv_property_dump(tvp);
+
+       /* Allow the frontend to validate incoming properties */
+       if (fe->ops.get_property)
+               r = fe->ops.get_property(fe, tvp);
+
+       if (r < 0)
+               return r;
+
+       switch(tvp->cmd) {
+       case DTV_FREQUENCY:
+               tvp->u.data = fe->dtv_property_cache.frequency;
+               break;
+       case DTV_MODULATION:
+               tvp->u.data = fe->dtv_property_cache.modulation;
+               break;
+       case DTV_BANDWIDTH_HZ:
+               tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
+               break;
+       case DTV_INVERSION:
+               tvp->u.data = fe->dtv_property_cache.inversion;
+               break;
+       case DTV_SYMBOL_RATE:
+               tvp->u.data = fe->dtv_property_cache.symbol_rate;
+               break;
+       case DTV_INNER_FEC:
+               tvp->u.data = fe->dtv_property_cache.fec_inner;
+               break;
+       case DTV_PILOT:
+               tvp->u.data = fe->dtv_property_cache.pilot;
+               break;
+       case DTV_ROLLOFF:
+               tvp->u.data = fe->dtv_property_cache.rolloff;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+               tvp->u.data = fe->dtv_property_cache.delivery_system;
+               break;
+       case DTV_VOLTAGE:
+               tvp->u.data = fe->dtv_property_cache.voltage;
+               break;
+       case DTV_TONE:
+               tvp->u.data = fe->dtv_property_cache.sectone;
+               break;
+       case DTV_API_VERSION:
+               tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+               break;
+       case DTV_CODE_RATE_HP:
+               tvp->u.data = fe->dtv_property_cache.code_rate_HP;
+               break;
+       case DTV_CODE_RATE_LP:
+               tvp->u.data = fe->dtv_property_cache.code_rate_LP;
+               break;
+       case DTV_GUARD_INTERVAL:
+               tvp->u.data = fe->dtv_property_cache.guard_interval;
+               break;
+       case DTV_TRANSMISSION_MODE:
+               tvp->u.data = fe->dtv_property_cache.transmission_mode;
+               break;
+       case DTV_HIERARCHY:
+               tvp->u.data = fe->dtv_property_cache.hierarchy;
+               break;
+       default:
+               r = -1;
+       }
+
+       return r;
+}
+
+int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
+       struct inode *inode, struct file *file)
+{
+       int r = 0;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       printk("%s()\n", __FUNCTION__);
+       dtv_property_dump(tvp);
+
+       /* Allow the frontend to validate incoming properties */
+       if (fe->ops.set_property)
+               r = fe->ops.set_property(fe, tvp);
+
+       if (r < 0)
+               return r;
+
+       switch(tvp->cmd) {
+       case DTV_CLEAR:
+               /* Reset a cache of data specific to the frontend here. This does
+                * not effect hardware.
+                */
+               printk("%s() Flushing property cache\n", __FUNCTION__);
+               memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));
+               fe->dtv_property_cache.state = tvp->cmd;
+               fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
+               break;
+       case DTV_TUNE:
+               /* interpret the cache of data, build either a traditional frontend
+                * tunerequest so we can pass validation in the FE_SET_FRONTEND
+                * ioctl.
+                */
+               fe->dtv_property_cache.state = tvp->cmd;
+               printk("%s() Finalised property cache\n", __FUNCTION__);
+               dtv_property_cache_submit(fe);
+
+               r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
+                       &fepriv->parameters);
+               break;
+       case DTV_FREQUENCY:
+               fe->dtv_property_cache.frequency = tvp->u.data;
+               break;
+       case DTV_MODULATION:
+               fe->dtv_property_cache.modulation = tvp->u.data;
+               break;
+       case DTV_BANDWIDTH_HZ:
+               fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
+               break;
+       case DTV_INVERSION:
+               fe->dtv_property_cache.inversion = tvp->u.data;
+               break;
+       case DTV_SYMBOL_RATE:
+               fe->dtv_property_cache.symbol_rate = tvp->u.data;
+               break;
+       case DTV_INNER_FEC:
+               fe->dtv_property_cache.fec_inner = tvp->u.data;
+               break;
+       case DTV_PILOT:
+               fe->dtv_property_cache.pilot = tvp->u.data;
+               break;
+       case DTV_ROLLOFF:
+               fe->dtv_property_cache.rolloff = tvp->u.data;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+               fe->dtv_property_cache.delivery_system = tvp->u.data;
+               break;
+       case DTV_VOLTAGE:
+               fe->dtv_property_cache.voltage = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE,
+                       (void *)fe->dtv_property_cache.voltage);
+               break;
+       case DTV_TONE:
+               fe->dtv_property_cache.sectone = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,
+                       (void *)fe->dtv_property_cache.sectone);
+               break;
+       case DTV_CODE_RATE_HP:
+               fe->dtv_property_cache.code_rate_HP = tvp->u.data;
+               break;
+       case DTV_CODE_RATE_LP:
+               fe->dtv_property_cache.code_rate_LP = tvp->u.data;
+               break;
+       case DTV_GUARD_INTERVAL:
+               fe->dtv_property_cache.guard_interval = tvp->u.data;
+               break;
+       case DTV_TRANSMISSION_MODE:
+               fe->dtv_property_cache.transmission_mode = tvp->u.data;
+               break;
+       case DTV_HIERARCHY:
+               fe->dtv_property_cache.hierarchy = tvp->u.data;
+               break;
+       default:
+               r = -1;
+       }
+
+       return r;
+}
+
 static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, void *parg)
 {
@@ -776,6 +1310,116 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
        if (down_interruptible (&fepriv->sem))
                return -ERESTARTSYS;
 
+       if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+               err = dvb_frontend_ioctl_properties(inode, file, cmd, parg);
+       else {
+               fe->dtv_property_cache.state = DTV_UNDEFINED;
+               err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg);
+       }
+
+       up(&fepriv->sem);
+       return err;
+}
+
+static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
+                       unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       int err = 0;
+
+       struct dtv_properties *tvps = NULL;
+       struct dtv_property *tvp = NULL;
+       int i;
+
+       dprintk("%s\n", __func__);
+
+       if(cmd == FE_SET_PROPERTY) {
+               printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
+
+               tvps = (struct dtv_properties __user *)parg;
+
+               printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
+               printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+
+               /* Put an arbitrary limit on the number of messages that can
+                * be sent at once */
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = (struct dtv_property *) kmalloc(tvps->num *
+                       sizeof(struct dtv_property), GFP_KERNEL);
+               if (!tvp) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+               for (i = 0; i < tvps->num; i++) {
+                       (tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file);
+                       err |= (tvp + i)->result;
+               }
+
+               if(fe->dtv_property_cache.state == DTV_TUNE) {
+                       printk("%s() Property cache is full, tuning\n", __FUNCTION__);
+               }
+
+       } else
+       if(cmd == FE_GET_PROPERTY) {
+               printk("%s() FE_GET_PROPERTY\n", __FUNCTION__);
+
+               tvps = (struct dtv_properties __user *)parg;
+
+               printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
+               printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+
+               /* Put an arbitrary limit on the number of messages that can
+                * be sent at once */
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = (struct dtv_property *) kmalloc(tvps->num *
+                       sizeof(struct dtv_property), GFP_KERNEL);
+               if (!tvp) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+               for (i = 0; i < tvps->num; i++) {
+                       (tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file);
+                       err |= (tvp + i)->result;
+               }
+
+               if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+       } else
+               err = -EOPNOTSUPP;
+
+out:
+       kfree(tvp);
+       return err;
+}
+
+static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
+                       unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       int err = -EOPNOTSUPP;
+
        switch (cmd) {
        case FE_GET_INFO: {
                struct dvb_frontend_info* info = parg;
@@ -942,13 +1586,21 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
        case FE_SET_FRONTEND: {
                struct dvb_frontend_tune_settings fetunesettings;
 
-               if (dvb_frontend_check_parameters(fe, parg) < 0) {
-                       err = -EINVAL;
-                       break;
-               }
+               if(fe->dtv_property_cache.state == DTV_TUNE) {
+                       if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
+                               err = -EINVAL;
+                               break;
+                       }
+               } else {
+                       if (dvb_frontend_check_parameters(fe, parg) < 0) {
+                               err = -EINVAL;
+                               break;
+                       }
 
-               memcpy (&fepriv->parameters, parg,
-                       sizeof (struct dvb_frontend_parameters));
+                       memcpy (&fepriv->parameters, parg,
+                               sizeof (struct dvb_frontend_parameters));
+                       dtv_property_cache_sync(fe, &fepriv->parameters);
+               }
 
                memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
                memcpy(&fetunesettings.parameters, parg,
@@ -1027,10 +1679,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                break;
        };
 
-       up (&fepriv->sem);
        return err;
 }
 
+
 static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct dvb_device *dvbdev = file->private_data;
index aa4133f..3055301 100644 (file)
@@ -169,6 +169,9 @@ struct dvb_frontend_ops {
 
        struct dvb_tuner_ops tuner_ops;
        struct analog_demod_ops analog_ops;
+
+       int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+       int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
 };
 
 #define MAX_EVENT 8
@@ -182,6 +185,32 @@ struct dvb_fe_events {
        struct mutex              mtx;
 };
 
+struct dtv_frontend_properties {
+
+       /* Cache State */
+       u32                     state;
+
+       u32                     frequency;
+       fe_modulation_t         modulation;
+
+       fe_sec_voltage_t        voltage;
+       fe_sec_tone_mode_t      sectone;
+       fe_spectral_inversion_t inversion;
+       fe_code_rate_t          fec_inner;
+       fe_transmit_mode_t      transmission_mode;
+       u32                     bandwidth_hz;   /* 0 = AUTO */
+       fe_guard_interval_t     guard_interval;
+       fe_hierarchy_t          hierarchy;
+       u32                     symbol_rate;
+       fe_code_rate_t          code_rate_HP;
+       fe_code_rate_t          code_rate_LP;
+
+       fe_pilot_t              pilot;
+       fe_rolloff_t            rolloff;
+
+       fe_delivery_system_t    delivery_system;
+};
+
 struct dvb_frontend {
        struct dvb_frontend_ops ops;
        struct dvb_adapter *dvb;
@@ -190,6 +219,9 @@ struct dvb_frontend {
        void *frontend_priv;
        void *sec_priv;
        void *analog_demod_priv;
+       struct dtv_frontend_properties dtv_property_cache;
+#define DVB_FRONTEND_COMPONENT_TUNER 0
+       int (*callback)(void *adapter_priv, int component, int cmd, int arg);
 };
 
 extern int dvb_register_frontend(struct dvb_adapter *dvb,
index e84152b..3c13bcf 100644 (file)
@@ -72,9 +72,11 @@ config DVB_USB_DIB0700
        select DVB_DIB7000P
        select DVB_DIB7000M
        select DVB_DIB3000MC
+       select DVB_S5H1411 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
        select DVB_TUNER_DIB0070
        help
          Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
@@ -108,6 +110,8 @@ config DVB_USB_CXUSB
        select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+       select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the Conexant USB2.0 hybrid reference design.
          Currently, only DVB and ATSC modes are supported, analog mode
@@ -245,12 +249,25 @@ config DVB_USB_AF9005_REMOTE
          Afatech AF9005 based receiver.
 
 config DVB_USB_DW2102
-       tristate "DvbWorld 2102 DVB-S USB2.0 receiver"
+       tristate "DvbWorld DVB-S/S2 USB2.0 support"
        depends on DVB_USB
-       select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_PLL if !DVB_FE_CUSTOMISE
+       select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_STV0288 if !DVB_FE_CUSTOMISE
+       select DVB_STB6000 if !DVB_FE_CUSTOMISE
+       select DVB_CX24116 if !DVB_FE_CUSTOMISE
+       select DVB_SI21XX if !DVB_FE_CUSTOMISE
        help
-          Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver.
+         Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
+         and the TeVii S650.
+
+config         DVB_USB_CINERGY_T2
+       tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
+       depends on DVB_USB
+       help
+         Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
+
+         Say Y if you own such a device and want to use it.
 
 config DVB_USB_ANYSEE
        tristate "Anysee DVB-T/C USB2.0 support"
@@ -262,3 +279,22 @@ config DVB_USB_ANYSEE
        help
          Say Y here to support the Anysee E30, Anysee E30 Plus or
          Anysee E30 C Plus DVB USB2.0 receiver.
+
+config DVB_USB_DTV5100
+       tristate "AME DTV-5100 USB2.0 DVB-T support"
+       depends on DVB_USB
+       select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
+
+config DVB_USB_AF9015
+       tristate "Afatech AF9015 DVB-T USB2.0 support"
+       depends on DVB_USB && EXPERIMENTAL
+       select DVB_AF9013
+       select DVB_PLL              if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_MT2060   if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_QT1010   if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
index e206f1e..3122b7c 100644 (file)
@@ -67,6 +67,16 @@ obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
 dvb-usb-dw2102-objs = dw2102.o
 obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
 
+dvb-usb-dtv5100-objs = dtv5100.o
+obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
+
+dvb-usb-af9015-objs = af9015.o
+obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
+
+dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
+obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
+
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
index ff00c0e..7c596f9 100644 (file)
@@ -25,7 +25,7 @@
  */
 #include "af9005.h"
 /* debug */
-int dvb_usb_af9005_remote_debug;
+static int dvb_usb_af9005_remote_debug;
 module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
 MODULE_PARM_DESC(debug,
                 "enable (1) or disable (0) debug messages."
index 6eeaae5..4d69045 100644 (file)
@@ -14,7 +14,7 @@ typedef struct {
        u8 val;
 } RegDesc;
 
-RegDesc script[] = {
+static RegDesc script[] = {
        {0xa180, 0x0, 0x8, 0xa},
        {0xa181, 0x0, 0x8, 0xd7},
        {0xa182, 0x0, 0x8, 0xa3},
index cfe71fe..ca5a0a4 100644 (file)
@@ -35,17 +35,17 @@ module_param_named(led, dvb_usb_af9005_led, bool, 0644);
 MODULE_PARM_DESC(led, "enable led (default: 1).");
 
 /* eeprom dump */
-int dvb_usb_af9005_dump_eeprom = 0;
+static int dvb_usb_af9005_dump_eeprom;
 module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
 MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /* remote control decoder */
-int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
-                 int *state);
-void *rc_keys;
-int *rc_keys_size;
+static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len,
+               u32 *event, int *state);
+static void *rc_keys;
+static int *rc_keys_size;
 
 u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
 
@@ -54,8 +54,8 @@ struct af9005_device_state {
        int led_state;
 };
 
-int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
-                         u8 * rbuf, u16 rlen, int delay_ms)
+static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen,
+                         u8 *rbuf, u16 rlen, int delay_ms)
 {
        int actlen, ret = -ENOMEM;
 
@@ -98,12 +98,7 @@ int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
        return ret;
 }
 
-int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
-{
-       return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
-}
-
-int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
                              int readwrite, int type, u8 * values, int len)
 {
        struct af9005_device_state *st = d->priv;
@@ -765,7 +760,7 @@ static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
        return 0;
 }
 
-int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
 {
        int i, packets, ret, act_len;
 
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
new file mode 100644 (file)
index 0000000..cb0829c
--- /dev/null
@@ -0,0 +1,1474 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    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 "af9015.h"
+#include "af9013.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include "tda18271.h"
+#include "mxl5005s.h"
+#if 0
+#include "mc44s80x.h"
+#endif
+
+int dvb_usb_af9015_debug;
+module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+int dvb_usb_af9015_remote;
+module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
+MODULE_PARM_DESC(remote, "select remote");
+int dvb_usb_af9015_dual_mode;
+module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644);
+MODULE_PARM_DESC(dual_mode, "enable dual mode");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static DEFINE_MUTEX(af9015_usb_mutex);
+
+static struct af9015_config af9015_config;
+static struct dvb_usb_device_properties af9015_properties[2];
+int af9015_properties_count = ARRAY_SIZE(af9015_properties);
+
+static struct af9013_config af9015_af9013_config[] = {
+       {
+               .demod_address = AF9015_I2C_DEMOD,
+               .output_mode = AF9013_OUTPUT_MODE_USB,
+               .api_version = { 0, 1, 9, 0 },
+               .gpio[0] = AF9013_GPIO_HI,
+               .gpio[3] = AF9013_GPIO_TUNER_ON,
+
+       }, {
+               .output_mode = AF9013_OUTPUT_MODE_SERIAL,
+               .api_version = { 0, 1, 9, 0 },
+               .gpio[0] = AF9013_GPIO_TUNER_ON,
+               .gpio[1] = AF9013_GPIO_LO,
+       }
+};
+
+static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
+{
+       int act_len, ret;
+       u8 buf[64];
+       u8 write = 1;
+       u8 msg_len = 8;
+       static u8 seq; /* packet sequence number */
+
+       if (mutex_lock_interruptible(&af9015_usb_mutex) < 0)
+               return -EAGAIN;
+
+       buf[0] = req->cmd;
+       buf[1] = seq++;
+       buf[2] = req->i2c_addr;
+       buf[3] = req->addr >> 8;
+       buf[4] = req->addr & 0xff;
+       buf[5] = req->mbox;
+       buf[6] = req->addr_len;
+       buf[7] = req->data_len;
+
+       switch (req->cmd) {
+       case GET_CONFIG:
+       case BOOT:
+       case READ_MEMORY:
+       case RECONNECT_USB:
+       case GET_IR_CODE:
+               write = 0;
+               break;
+       case READ_I2C:
+               write = 0;
+               buf[2] |= 0x01; /* set I2C direction */
+       case WRITE_I2C:
+               buf[0] = READ_WRITE_I2C;
+               break;
+       case WRITE_MEMORY:
+               if (((req->addr & 0xff00) == 0xff00) ||
+                   ((req->addr & 0xae00) == 0xae00))
+                       buf[0] = WRITE_VIRTUAL_MEMORY;
+       case WRITE_VIRTUAL_MEMORY:
+       case COPY_FIRMWARE:
+       case DOWNLOAD_FIRMWARE:
+               break;
+       default:
+               err("unknown command:%d", req->cmd);
+               ret = -1;
+               goto error_unlock;
+       }
+
+       /* write requested */
+       if (write) {
+               memcpy(&buf[8], req->data, req->data_len);
+               msg_len += req->data_len;
+       }
+       deb_xfer(">>> ");
+       debug_dump(buf, msg_len, deb_xfer);
+
+       /* send req */
+       ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
+       &act_len, AF9015_USB_TIMEOUT);
+       if (ret)
+               err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len);
+       else
+               if (act_len != msg_len)
+                       ret = -1; /* all data is not send */
+       if (ret)
+               goto error_unlock;
+
+       /* no ack for those packets */
+       if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
+               goto exit_unlock;
+
+       /* receive ack and data if read req */
+       msg_len = 1 + 1 + req->data_len;  /* seq + status + data len */
+       ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
+                          &act_len, AF9015_USB_TIMEOUT);
+       if (ret) {
+               err("recv bulk message failed:%d", ret);
+               ret = -1;
+               goto error_unlock;
+       }
+
+       deb_xfer("<<< ");
+       debug_dump(buf, act_len, deb_xfer);
+
+       /* remote controller query status is 1 if remote code is not received */
+       if (req->cmd == GET_IR_CODE && buf[1] == 1) {
+               buf[1] = 0; /* clear command "error" status */
+               memset(&buf[2], 0, req->data_len);
+               buf[3] = 1; /* no remote code received mark */
+       }
+
+       /* check status */
+       if (buf[1]) {
+               err("command failed:%d", buf[1]);
+               ret = -1;
+               goto error_unlock;
+       }
+
+       /* read request, copy returned data to return buf */
+       if (!write)
+               memcpy(req->data, &buf[2], req->data_len);
+
+error_unlock:
+exit_unlock:
+       mutex_unlock(&af9015_usb_mutex);
+
+       return ret;
+}
+
+static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
+{
+       return af9015_rw_udev(d->udev, req);
+}
+
+static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
+       u8 len)
+{
+       struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+               val};
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
+{
+       return af9015_write_regs(d, addr, &val, 1);
+}
+
+static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+{
+       struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val};
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+       u8 val)
+{
+       struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
+
+       if (addr == af9015_af9013_config[0].demod_address ||
+           addr == af9015_af9013_config[1].demod_address)
+               req.addr_len = 3;
+
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+       u8 *val)
+{
+       struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
+
+       if (addr == af9015_af9013_config[0].demod_address ||
+           addr == af9015_af9013_config[1].demod_address)
+               req.addr_len = 3;
+
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+       int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0, i = 0;
+       u16 addr;
+       u8 mbox, addr_len;
+       struct req_t req;
+
+/* TODO: implement bus lock
+
+The bus lock is needed because there is two tuners both using same I2C-address.
+Due to that the only way to select correct tuner is use demodulator I2C-gate.
+
+................................................
+. AF9015 includes integrated AF9013 demodulator.
+. ____________                   ____________  .                ____________
+.|     uC     |                 |   demod    | .               |    tuner   |
+.|------------|                 |------------| .               |------------|
+.|   AF9015   |                 |  AF9013/5  | .               |   MXL5003  |
+.|            |--+----I2C-------|-----/ -----|-.-----I2C-------|            |
+.|            |  |              | addr 0x38  | .               |  addr 0xc6 |
+.|____________|  |              |____________| .               |____________|
+.................|..............................
+                |               ____________                   ____________
+                |              |   demod    |                 |    tuner   |
+                |              |------------|                 |------------|
+                |              |   AF9013   |                 |   MXL5003  |
+                +----I2C-------|-----/ -----|-------I2C-------|            |
+                               | addr 0x3a  |                 |  addr 0xc6 |
+                               |____________|                 |____________|
+*/
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       while (i < num) {
+               if (msg[i].addr == af9015_af9013_config[0].demod_address ||
+                   msg[i].addr == af9015_af9013_config[1].demod_address) {
+                       addr = msg[i].buf[0] << 8;
+                       addr += msg[i].buf[1];
+                       mbox = msg[i].buf[2];
+                       addr_len = 3;
+               } else {
+                       addr = msg[i].buf[0];
+                       addr_len = 1;
+                       mbox = 0;
+               }
+
+               if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+                       if (msg[i].addr ==
+                               af9015_af9013_config[0].demod_address)
+                               req.cmd = READ_MEMORY;
+                       else
+                               req.cmd = READ_I2C;
+                       req.i2c_addr = msg[i].addr;
+                       req.addr = addr;
+                       req.mbox = mbox;
+                       req.addr_len = addr_len;
+                       req.data_len = msg[i+1].len;
+                       req.data = &msg[i+1].buf[0];
+                       ret = af9015_ctrl_msg(d, &req);
+                       i += 2;
+               } else {
+                       if (msg[i].addr ==
+                               af9015_af9013_config[0].demod_address)
+                               req.cmd = WRITE_MEMORY;
+                       else
+                               req.cmd = WRITE_I2C;
+                       req.i2c_addr = msg[i].addr;
+                       req.addr = addr;
+                       req.mbox = mbox;
+                       req.addr_len = addr_len;
+                       req.data_len = msg[i].len-addr_len;
+                       req.data = &msg[i].buf[addr_len];
+                       ret = af9015_ctrl_msg(d, &req);
+                       i += 1;
+               }
+               if (ret)
+                       goto error;
+
+       }
+       ret = i;
+
+error:
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret;
+}
+
+static u32 af9015_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9015_i2c_algo = {
+       .master_xfer = af9015_i2c_xfer,
+       .functionality = af9015_i2c_func,
+};
+
+static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
+{
+       int ret;
+       u8 val, mask = 0x01;
+
+       ret = af9015_read_reg(d, addr, &val);
+       if (ret)
+               return ret;
+
+       mask <<= bit;
+       if (op) {
+               /* set bit */
+               val |= mask;
+       } else {
+               /* clear bit */
+               mask ^= 0xff;
+               val &= mask;
+       }
+
+       return af9015_write_reg(d, addr, val);
+}
+
+static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+       return af9015_do_reg_bit(d, addr, bit, 1);
+}
+
+static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+       return af9015_do_reg_bit(d, addr, bit, 0);
+}
+
+static int af9015_init_endpoint(struct dvb_usb_device *d)
+{
+       int ret;
+       u16 frame_size;
+       u8  packet_size;
+       deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
+
+#define TS_PACKET_SIZE            188
+
+#define TS_USB20_PACKET_COUNT     348
+#define TS_USB20_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
+
+#define TS_USB11_PACKET_COUNT      21
+#define TS_USB11_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
+
+#define TS_USB20_MAX_PACKET_SIZE  512
+#define TS_USB11_MAX_PACKET_SIZE   64
+
+       if (d->udev->speed == USB_SPEED_FULL) {
+               frame_size = TS_USB11_FRAME_SIZE/4;
+               packet_size = TS_USB11_MAX_PACKET_SIZE/4;
+       } else {
+               frame_size = TS_USB20_FRAME_SIZE/4;
+               packet_size = TS_USB20_MAX_PACKET_SIZE/4;
+       }
+
+       ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
+       if (ret)
+               goto error;
+       ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
+       if (ret)
+               goto error;
+       ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
+       if (ret)
+               goto error;
+       ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
+       if (ret)
+               goto error;
+       ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
+       if (ret)
+               goto error;
+       if (af9015_config.dual_mode) {
+               ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
+               if (ret)
+                       goto error;
+       }
+       ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
+       if (ret)
+               goto error;
+       if (af9015_config.dual_mode) {
+               ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
+               if (ret)
+                       goto error;
+       }
+       /* EP4 xfer length */
+       ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
+       if (ret)
+               goto error;
+       /* EP5 xfer length */
+       ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
+       if (ret)
+               goto error;
+       ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
+       if (ret)
+               goto error;
+       if (af9015_config.dual_mode) {
+               ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
+               if (ret)
+                       goto error;
+       }
+
+       /* enable / disable mp2if2 */
+       if (af9015_config.dual_mode)
+               ret = af9015_set_reg_bit(d, 0xd50b, 0);
+       else
+               ret = af9015_clear_reg_bit(d, 0xd50b, 0);
+error:
+       if (ret)
+               err("endpoint init failed:%d", ret);
+       return ret;
+}
+
+static int af9015_copy_firmware(struct dvb_usb_device *d)
+{
+       int ret;
+       u8 fw_params[4];
+       u8 val, i;
+       struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
+               fw_params };
+       deb_info("%s:\n", __func__);
+
+       fw_params[0] = af9015_config.firmware_size >> 8;
+       fw_params[1] = af9015_config.firmware_size & 0xff;
+       fw_params[2] = af9015_config.firmware_checksum >> 8;
+       fw_params[3] = af9015_config.firmware_checksum & 0xff;
+
+       /* wait 2nd demodulator ready */
+       msleep(100);
+
+       ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val);
+       if (ret)
+               goto error;
+       else
+               deb_info("%s: firmware status:%02x\n", __func__, val);
+
+       if (val == 0x0c) /* fw is running, no need for download */
+               goto exit;
+
+       /* set I2C master clock to fast (to speed up firmware copy) */
+       ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
+       if (ret)
+               goto error;
+
+       msleep(50);
+
+       /* copy firmware */
+       ret = af9015_ctrl_msg(d, &req);
+       if (ret)
+               err("firmware copy cmd failed:%d", ret);
+       deb_info("%s: firmware copy done\n", __func__);
+
+       /* set I2C master clock back to normal */
+       ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
+       if (ret)
+               goto error;
+
+       /* request boot firmware */
+       ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address,
+               0xe205, 1);
+       deb_info("%s: firmware boot cmd status:%d\n", __func__, ret);
+       if (ret)
+               goto error;
+
+       for (i = 0; i < 15; i++) {
+               msleep(100);
+
+               /* check firmware status */
+               ret = af9015_read_reg_i2c(d,
+                       af9015_af9013_config[1].demod_address, 0x98be, &val);
+               deb_info("%s: firmware status cmd status:%d fw status:%02x\n",
+                       __func__, ret, val);
+               if (ret)
+                       goto error;
+
+               if (val == 0x0c || val == 0x04) /* success or fail */
+                       break;
+       }
+
+       if (val == 0x04) {
+               err("firmware did not run");
+               ret = -1;
+       } else if (val != 0x0c) {
+               err("firmware boot timeout");
+               ret = -1;
+       }
+
+error:
+exit:
+       return ret;
+}
+
+/* dump eeprom */
+static int af9015_eeprom_dump(struct dvb_usb_device *d)
+{
+       char buf[52], buf2[4];
+       u8 reg, val;
+
+       for (reg = 0; ; reg++) {
+               if (reg % 16 == 0) {
+                       if (reg)
+                               deb_info("%s\n", buf);
+                       sprintf(buf, "%02x: ", reg);
+               }
+               if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0)
+                       sprintf(buf2, "%02x ", val);
+               else
+                       strcpy(buf2, "-- ");
+               strcat(buf, buf2);
+               if (reg == 0xff)
+                       break;
+       }
+       deb_info("%s\n", buf);
+       return 0;
+}
+
+int af9015_download_ir_table(struct dvb_usb_device *d)
+{
+       int i, packets = 0, ret;
+       u16 addr = 0x9a56; /* ir-table start address */
+       struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL};
+       u8 *data = NULL;
+       deb_info("%s:\n", __func__);
+
+       data = af9015_config.ir_table;
+       packets = af9015_config.ir_table_size;
+
+       /* no remote */
+       if (!packets)
+               goto exit;
+
+       /* load remote ir-table */
+       for (i = 0; i < packets; i++) {
+               req.addr = addr + i;
+               req.data = &data[i];
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret) {
+                       err("ir-table download failed at packet %d with " \
+                               "code %d", i, ret);
+                       return ret;
+               }
+       }
+
+exit:
+       return 0;
+}
+
+static int af9015_init(struct dvb_usb_device *d)
+{
+       int ret;
+       deb_info("%s:\n", __func__);
+
+       ret = af9015_init_endpoint(d);
+       if (ret)
+               goto error;
+
+       ret = af9015_download_ir_table(d);
+       if (ret)
+               goto error;
+
+error:
+       return ret;
+}
+
+static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       int ret;
+       deb_info("%s: onoff:%d\n", __func__, onoff);
+
+       if (onoff)
+               ret = af9015_set_reg_bit(adap->dev, 0xd503, 0);
+       else
+               ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0);
+
+       return ret;
+}
+
+static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+       int onoff)
+{
+       int ret;
+       u8 idx;
+
+       deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n",
+               __func__, index, pid, onoff);
+
+       ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff));
+       if (ret)
+               goto error;
+
+       ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8));
+       if (ret)
+               goto error;
+
+       idx = ((index & 0x1f) | (1 << 5));
+       ret = af9015_write_reg(adap->dev, 0xd504, idx);
+
+error:
+       return ret;
+}
+
+static int af9015_download_firmware(struct usb_device *udev,
+       const struct firmware *fw)
+{
+       int i, len, packets, remainder, ret;
+       struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
+       u16 addr = 0x5100; /* firmware start address */
+       u16 checksum = 0;
+
+       deb_info("%s:\n", __func__);
+
+       /* calc checksum */
+       for (i = 0; i < fw->size; i++)
+               checksum += fw->data[i];
+
+       af9015_config.firmware_size = fw->size;
+       af9015_config.firmware_checksum = checksum;
+
+       #define FW_PACKET_MAX_DATA  55
+
+       packets = fw->size / FW_PACKET_MAX_DATA;
+       remainder = fw->size % FW_PACKET_MAX_DATA;
+       len = FW_PACKET_MAX_DATA;
+       for (i = 0; i <= packets; i++) {
+               if (i == packets)  /* set size of the last packet */
+                       len = remainder;
+
+               req.data_len = len;
+               req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
+               req.addr = addr;
+               addr += FW_PACKET_MAX_DATA;
+
+               ret = af9015_rw_udev(udev, &req);
+               if (ret) {
+                       err("firmware download failed at packet %d with " \
+                               "code %d", i, ret);
+                       goto error;
+               }
+       }
+
+       /* firmware loaded, request boot */
+       req.cmd = BOOT;
+       ret = af9015_rw_udev(udev, &req);
+       if (ret) {
+               err("firmware boot failed:%d", ret);
+               goto error;
+       }
+
+       /* firmware is running, reconnect device in the usb bus */
+       req.cmd = RECONNECT_USB;
+       ret = af9015_rw_udev(udev, &req);
+       if (ret)
+               err("reconnect failed: %d", ret);
+
+error:
+       return ret;
+}
+
+static int af9015_read_config(struct usb_device *udev)
+{
+       int ret;
+       u8 val, i, offset = 0;
+       struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+       char manufacturer[10];
+
+       /* IR remote controller */
+       req.addr = AF9015_EEPROM_IR_MODE;
+       ret = af9015_rw_udev(udev, &req);
+       if (ret)
+               goto error;
+       deb_info("%s: IR mode:%d\n", __func__, val);
+       for (i = 0; i < af9015_properties_count; i++) {
+               if (val == AF9015_IR_MODE_DISABLED || val == 0x04) {
+                       af9015_properties[i].rc_key_map = NULL;
+                       af9015_properties[i].rc_key_map_size  = 0;
+               } else if (dvb_usb_af9015_remote) {
+                       /* load remote defined as module param */
+                       switch (dvb_usb_af9015_remote) {
+                       case AF9015_REMOTE_A_LINK_DTU_M:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_a_link;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_a_link);
+                               af9015_config.ir_table = af9015_ir_table_a_link;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_a_link);
+                               break;
+                       case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_msi;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_msi);
+                               af9015_config.ir_table = af9015_ir_table_msi;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_msi);
+                               break;
+                       case AF9015_REMOTE_MYGICTV_U718:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_mygictv;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_mygictv);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_mygictv;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_mygictv);
+                               break;
+                       }
+               } else {
+                       switch (udev->descriptor.idVendor) {
+                       case USB_VID_LEADTEK:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_leadtek;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_leadtek);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_leadtek;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_leadtek);
+                               break;
+                       case USB_VID_VISIONPLUS:
+                               if (udev->descriptor.idProduct ==
+                               USB_PID_AZUREWAVE_AD_TU700) {
+                                       af9015_properties[i].rc_key_map =
+                                         af9015_rc_keys_twinhan;
+                                       af9015_properties[i].rc_key_map_size =
+                                         ARRAY_SIZE(af9015_rc_keys_twinhan);
+                                       af9015_config.ir_table =
+                                         af9015_ir_table_twinhan;
+                                       af9015_config.ir_table_size =
+                                         ARRAY_SIZE(af9015_ir_table_twinhan);
+                               }
+                               break;
+                       case USB_VID_KWORLD_2:
+                               /* TODO: use correct rc keys */
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_twinhan;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_twinhan);
+                               af9015_config.ir_table = af9015_ir_table_kworld;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_kworld);
+                               break;
+                       /* Check USB manufacturer and product strings and try
+                          to determine correct remote in case of chip vendor
+                          reference IDs are used. */
+                       case USB_VID_AFATECH:
+                               memset(manufacturer, 0, sizeof(manufacturer));
+                               usb_string(udev, udev->descriptor.iManufacturer,
+                                       manufacturer, sizeof(manufacturer));
+                               if (!strcmp("Geniatech", manufacturer)) {
+                                       /* iManufacturer 1 Geniatech
+                                          iProduct      2 AF9015 */
+                                       af9015_properties[i].rc_key_map =
+                                         af9015_rc_keys_mygictv;
+                                       af9015_properties[i].rc_key_map_size =
+                                         ARRAY_SIZE(af9015_rc_keys_mygictv);
+                                       af9015_config.ir_table =
+                                         af9015_ir_table_mygictv;
+                                       af9015_config.ir_table_size =
+                                         ARRAY_SIZE(af9015_ir_table_mygictv);
+                               } else if (!strcmp("MSI", manufacturer)) {
+                                       /* iManufacturer 1 MSI
+                                          iProduct      2 MSI K-VOX */
+                                       af9015_properties[i].rc_key_map =
+                                         af9015_rc_keys_msi;
+                                       af9015_properties[i].rc_key_map_size =
+                                         ARRAY_SIZE(af9015_rc_keys_msi);
+                                       af9015_config.ir_table =
+                                         af9015_ir_table_msi;
+                                       af9015_config.ir_table_size =
+                                         ARRAY_SIZE(af9015_ir_table_msi);
+                               }
+                               break;
+                       }
+               }
+       }
+
+       /* TS mode - one or two receivers */
+       req.addr = AF9015_EEPROM_TS_MODE;
+       ret = af9015_rw_udev(udev, &req);
+       if (ret)
+               goto error;
+       af9015_config.dual_mode = val;
+       deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode);
+       /* disable dual mode by default because it is buggy */
+       if (!dvb_usb_af9015_dual_mode)
+               af9015_config.dual_mode = 0;
+
+       /* set buffer size according to USB port speed */
+       for (i = 0; i < af9015_properties_count; i++) {
+               /* USB1.1 set smaller buffersize and disable 2nd adapter */
+               if (udev->speed == USB_SPEED_FULL) {
+                       af9015_properties[i].adapter->stream.u.bulk.buffersize =
+                               TS_USB11_MAX_PACKET_SIZE;
+                       /* disable 2nd adapter because we don't have
+                          PID-filters */
+                       af9015_config.dual_mode = 0;
+               } else {
+                       af9015_properties[i].adapter->stream.u.bulk.buffersize =
+                               TS_USB20_MAX_PACKET_SIZE;
+               }
+       }
+
+       if (af9015_config.dual_mode) {
+               /* read 2nd demodulator I2C address */
+               req.addr = AF9015_EEPROM_DEMOD2_I2C;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_af9013_config[1].demod_address = val;
+
+               /* enable 2nd adapter */
+               for (i = 0; i < af9015_properties_count; i++)
+                       af9015_properties[i].num_adapters = 2;
+
+       } else {
+                /* disable 2nd adapter */
+               for (i = 0; i < af9015_properties_count; i++)
+                       af9015_properties[i].num_adapters = 1;
+       }
+
+       for (i = 0; i < af9015_properties[0].num_adapters; i++) {
+               if (i == 1)
+                       offset = AF9015_EEPROM_OFFSET;
+               /* xtal */
+               req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               switch (val) {
+               case 0:
+                       af9015_af9013_config[i].adc_clock = 28800;
+                       break;
+               case 1:
+                       af9015_af9013_config[i].adc_clock = 20480;
+                       break;
+               case 2:
+                       af9015_af9013_config[i].adc_clock = 28000;
+                       break;
+               case 3:
+                       af9015_af9013_config[i].adc_clock = 25000;
+                       break;
+               };
+               deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i,
+                       val, af9015_af9013_config[i].adc_clock);
+
+               /* tuner IF */
+               req.addr = AF9015_EEPROM_IF1H + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_af9013_config[i].tuner_if = val << 8;
+               req.addr = AF9015_EEPROM_IF1L + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_af9013_config[i].tuner_if += val;
+               deb_info("%s: [%d] IF1:%d\n", __func__, i,
+                       af9015_af9013_config[0].tuner_if);
+
+               /* MT2060 IF1 */
+               req.addr = AF9015_EEPROM_MT2060_IF1H  + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_config.mt2060_if1[i] = val << 8;
+               req.addr = AF9015_EEPROM_MT2060_IF1L + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               af9015_config.mt2060_if1[i] += val;
+               deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i,
+                       af9015_config.mt2060_if1[i]);
+
+               /* tuner */
+               req.addr =  AF9015_EEPROM_TUNER_ID1 + offset;
+               ret = af9015_rw_udev(udev, &req);
+               if (ret)
+                       goto error;
+               switch (val) {
+               case AF9013_TUNER_ENV77H11D5:
+               case AF9013_TUNER_MT2060:
+               case AF9013_TUNER_MC44S803:
+               case AF9013_TUNER_QT1010:
+               case AF9013_TUNER_UNKNOWN:
+               case AF9013_TUNER_MT2060_2:
+               case AF9013_TUNER_TDA18271:
+               case AF9013_TUNER_QT1010A:
+                       af9015_af9013_config[i].rf_spec_inv = 1;
+                       break;
+               case AF9013_TUNER_MXL5003D:
+               case AF9013_TUNER_MXL5005D:
+               case AF9013_TUNER_MXL5005R:
+                       af9015_af9013_config[i].rf_spec_inv = 0;
+                       break;
+               default:
+                       warn("tuner id:%d not supported, please report!", val);
+                       return -ENODEV;
+               };
+
+               af9015_af9013_config[i].tuner = val;
+               deb_info("%s: [%d] tuner id:%d\n", __func__, i, val);
+       }
+
+error:
+       if (ret)
+               err("eeprom read failed:%d", ret);
+
+       return ret;
+}
+
+static int af9015_identify_state(struct usb_device *udev,
+                                struct dvb_usb_device_properties *props,
+                                struct dvb_usb_device_description **desc,
+                                int *cold)
+{
+       int ret;
+       u8 reply;
+       struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
+
+       ret = af9015_rw_udev(udev, &req);
+       if (ret)
+               return ret;
+
+       deb_info("%s: reply:%02x\n", __func__, reply);
+       if (reply == 0x02)
+               *cold = 0;
+       else
+               *cold = 1;
+
+       return ret;
+}
+
+static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+       u8 buf[8];
+       struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       int i, ret;
+
+       memset(buf, 0, sizeof(buf));
+
+       ret = af9015_ctrl_msg(d, &req);
+       if (ret)
+               return ret;
+
+       *event = 0;
+       *state = REMOTE_NO_KEY_PRESSED;
+
+       for (i = 0; i < d->props.rc_key_map_size; i++) {
+               if (!buf[1] && keymap[i].custom == buf[0] &&
+                   keymap[i].data == buf[2]) {
+                       *event = keymap[i].event;
+                       *state = REMOTE_KEY_PRESSED;
+                       break;
+               }
+       }
+       if (!buf[1])
+               deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+                       __func__, buf[0], buf[1], buf[2], buf[3], buf[4],
+                       buf[5], buf[6], buf[7]);
+
+       return 0;
+}
+
+/* init 2nd I2C adapter */
+int af9015_i2c_init(struct dvb_usb_device *d)
+{
+       int ret;
+       struct af9015_state *state = d->priv;
+       deb_info("%s:\n", __func__);
+
+       strncpy(state->i2c_adap.name, d->desc->name,
+               sizeof(state->i2c_adap.name));
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+       state->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
+#else
+       state->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
+#endif
+       state->i2c_adap.algo      = d->props.i2c_algo;
+       state->i2c_adap.algo_data = NULL;
+       state->i2c_adap.dev.parent = &d->udev->dev;
+
+       i2c_set_adapdata(&state->i2c_adap, d);
+
+       ret = i2c_add_adapter(&state->i2c_adap);
+       if (ret < 0)
+               err("could not add i2c adapter");
+
+       return ret;
+}
+
+static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       struct af9015_state *state = adap->dev->priv;
+       struct i2c_adapter *i2c_adap;
+
+       if (adap->id == 0) {
+               /* select I2C adapter */
+               i2c_adap = &adap->dev->i2c_adap;
+
+               deb_info("%s: init I2C\n", __func__);
+               ret = af9015_i2c_init(adap->dev);
+
+               /* dump eeprom (debug) */
+               ret = af9015_eeprom_dump(adap->dev);
+               if (ret)
+                       return ret;
+       } else {
+               /* select I2C adapter */
+               i2c_adap = &state->i2c_adap;
+
+               /* copy firmware to 2nd demodulator */
+               if (af9015_config.dual_mode) {
+                       ret = af9015_copy_firmware(adap->dev);
+                       if (ret) {
+                               err("firmware copy to 2nd frontend " \
+                                       "failed, will disable it");
+                               af9015_config.dual_mode = 0;
+                               return -ENODEV;
+                       }
+               } else {
+                       return -ENODEV;
+               }
+       }
+
+       /* attach demodulator */
+       adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
+               i2c_adap);
+
+       return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static struct mt2060_config af9015_mt2060_config = {
+       .i2c_address = 0xc0,
+       .clock_out = 0,
+};
+
+static struct qt1010_config af9015_qt1010_config = {
+       .i2c_address = 0xc4,
+};
+
+static struct tda18271_config af9015_tda18271_config = {
+       .gate = TDA18271_GATE_DIGITAL,
+       .small_i2c = 1,
+};
+
+static struct mxl5005s_config af9015_mxl5003_config = {
+       .i2c_address     = 0xc6,
+       .if_freq         = IF_FREQ_4570000HZ,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_DEFAULT,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
+
+static struct mxl5005s_config af9015_mxl5005_config = {
+       .i2c_address     = 0xc6,
+       .if_freq         = IF_FREQ_4570000HZ,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_OFF,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
+
+static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct af9015_state *state = adap->dev->priv;
+       struct i2c_adapter *i2c_adap;
+       int ret;
+       deb_info("%s: \n", __func__);
+
+       /* select I2C adapter */
+       if (adap->id == 0)
+               i2c_adap = &adap->dev->i2c_adap;
+       else
+               i2c_adap = &state->i2c_adap;
+
+       switch (af9015_af9013_config[adap->id].tuner) {
+       case AF9013_TUNER_MT2060:
+       case AF9013_TUNER_MT2060_2:
+               ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap,
+                       &af9015_mt2060_config,
+                       af9015_config.mt2060_if1[adap->id])
+                       == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_QT1010:
+       case AF9013_TUNER_QT1010A:
+               ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap,
+                       &af9015_qt1010_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_TDA18271:
+               ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap,
+                       &af9015_tda18271_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MXL5003D:
+               ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+                       &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MXL5005D:
+       case AF9013_TUNER_MXL5005R:
+               ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+                       &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_ENV77H11D5:
+               ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap,
+                       DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MC44S803:
+#if 0
+               ret = dvb_attach(mc44s80x_attach, adap->fe, i2c_adap)
+                       == NULL ? -ENODEV : 0;
+#else
+               ret = -ENODEV;
+               info("Freescale MC44S803 tuner found but no driver for that" \
+                       "tuner. Look at the Linuxtv.org for tuner driver" \
+                       "status.");
+#endif
+               break;
+       case AF9013_TUNER_UNKNOWN:
+       default:
+               ret = -ENODEV;
+               err("Unknown tuner id:%d",
+                       af9015_af9013_config[adap->id].tuner);
+       }
+       return ret;
+}
+
+static struct usb_device_id af9015_usb_table[] = {
+/*  0 */{USB_DEVICE(USB_VID_AFATECH,   USB_PID_AFATECH_AF9015_9015)},
+       {USB_DEVICE(USB_VID_AFATECH,   USB_PID_AFATECH_AF9015_9016)},
+       {USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_GOLD)},
+       {USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV71E)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_399U)},
+/*  5 */{USB_DEVICE(USB_VID_VISIONPLUS,
+               USB_PID_TINYTWIN)},
+       {USB_DEVICE(USB_VID_VISIONPLUS,
+               USB_PID_AZUREWAVE_AD_TU700)},
+       {USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_PC160_2T)},
+       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
+/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
+       {USB_DEVICE(USB_